Changed the root package from net.sf.briar to org.briarproject.

This commit is contained in:
akwizgran
2014-01-08 16:18:30 +00:00
parent dce70f487c
commit 832476412c
427 changed files with 2507 additions and 2507 deletions

View File

@@ -0,0 +1,220 @@
package org.briarproject.messaging;
import static org.briarproject.api.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.api.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.api.AuthorConstants.MAX_SIGNATURE_LENGTH;
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static org.briarproject.api.messaging.MessagingConstants.MAX_BODY_LENGTH;
import static org.briarproject.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
import static org.briarproject.api.messaging.MessagingConstants.MAX_GROUP_NAME_LENGTH;
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
import static org.briarproject.api.messaging.MessagingConstants.MAX_SUBSCRIPTIONS;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
import org.briarproject.BriarTestCase;
import org.briarproject.TestDatabaseModule;
import org.briarproject.TestLifecycleModule;
import org.briarproject.TestUtils;
import org.briarproject.api.Author;
import org.briarproject.api.AuthorFactory;
import org.briarproject.api.TransportId;
import org.briarproject.api.TransportProperties;
import org.briarproject.api.UniqueId;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyPair;
import org.briarproject.api.crypto.PrivateKey;
import org.briarproject.api.crypto.Signature;
import org.briarproject.api.messaging.Ack;
import org.briarproject.api.messaging.Group;
import org.briarproject.api.messaging.GroupFactory;
import org.briarproject.api.messaging.Message;
import org.briarproject.api.messaging.MessageFactory;
import org.briarproject.api.messaging.MessageId;
import org.briarproject.api.messaging.Offer;
import org.briarproject.api.messaging.PacketWriter;
import org.briarproject.api.messaging.PacketWriterFactory;
import org.briarproject.api.messaging.SubscriptionUpdate;
import org.briarproject.api.messaging.TransportUpdate;
import org.briarproject.crypto.CryptoModule;
import org.briarproject.db.DatabaseModule;
import org.briarproject.messaging.duplex.DuplexMessagingModule;
import org.briarproject.messaging.simplex.SimplexMessagingModule;
import org.briarproject.serial.SerialModule;
import org.briarproject.system.SystemModule;
import org.briarproject.transport.TransportModule;
import org.junit.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class ConstantsTest extends BriarTestCase {
private final CryptoComponent crypto;
private final GroupFactory groupFactory;
private final AuthorFactory authorFactory;
private final MessageFactory messageFactory;
private final PacketWriterFactory packetWriterFactory;
public ConstantsTest() throws Exception {
Injector i = Guice.createInjector(new TestDatabaseModule(),
new TestLifecycleModule(), new SystemModule(),
new CryptoModule(), new DatabaseModule(), new MessagingModule(),
new DuplexMessagingModule(), new SimplexMessagingModule(),
new SerialModule(), new TransportModule());
crypto = i.getInstance(CryptoComponent.class);
groupFactory = i.getInstance(GroupFactory.class);
authorFactory = i.getInstance(AuthorFactory.class);
messageFactory = i.getInstance(MessageFactory.class);
packetWriterFactory = i.getInstance(PacketWriterFactory.class);
}
@Test
public void testAgreementPublicKeys() throws Exception {
// Generate 10 agreement key pairs
for(int i = 0; i < 10; i++) {
KeyPair keyPair = crypto.generateSignatureKeyPair();
// Check the length of the public key
byte[] publicKey = keyPair.getPublic().getEncoded();
assertTrue(publicKey.length <= MAX_PUBLIC_KEY_LENGTH);
}
}
@Test
public void testSignaturePublicKeys() throws Exception {
Random random = new Random();
Signature sig = crypto.getSignature();
// Generate 10 signature key pairs
for(int i = 0; i < 10; i++) {
KeyPair keyPair = crypto.generateSignatureKeyPair();
// Check the length of the public key
byte[] publicKey = keyPair.getPublic().getEncoded();
assertTrue(publicKey.length <= MAX_PUBLIC_KEY_LENGTH);
// Sign some random data and check the length of the signature
byte[] toBeSigned = new byte[1234];
random.nextBytes(toBeSigned);
sig.initSign(keyPair.getPrivate());
sig.update(toBeSigned);
byte[] signature = sig.sign();
assertTrue("Length " + signature.length,
signature.length <= MAX_SIGNATURE_LENGTH);
}
}
@Test
public void testMessageIdsFitIntoLargeAck() throws Exception {
testMessageIdsFitIntoAck(MAX_PACKET_LENGTH);
}
@Test
public void testMessageIdsFitIntoSmallAck() throws Exception {
testMessageIdsFitIntoAck(1000);
}
@Test
public void testMessageFitsIntoPacket() throws Exception {
MessageId parent = new MessageId(TestUtils.getRandomId());
// Create a maximum-length group
String groupName = TestUtils.createRandomString(MAX_GROUP_NAME_LENGTH);
Group group = groupFactory.createGroup(groupName);
// Create a maximum-length author
String authorName =
TestUtils.createRandomString(MAX_AUTHOR_NAME_LENGTH);
byte[] authorPublic = new byte[MAX_PUBLIC_KEY_LENGTH];
Author author = authorFactory.createAuthor(authorName, authorPublic);
// Create a maximum-length message
PrivateKey privateKey = crypto.generateSignatureKeyPair().getPrivate();
String contentType =
TestUtils.createRandomString(MAX_CONTENT_TYPE_LENGTH);
long timestamp = Long.MAX_VALUE;
byte[] body = new byte[MAX_BODY_LENGTH];
Message message = messageFactory.createPseudonymousMessage(parent,
group, author, privateKey, contentType, timestamp, body);
// Check the size of the serialised message
int length = message.getSerialised().length;
assertTrue(length > UniqueId.LENGTH + MAX_GROUP_NAME_LENGTH
+ MAX_PUBLIC_KEY_LENGTH + MAX_AUTHOR_NAME_LENGTH
+ MAX_PUBLIC_KEY_LENGTH + MAX_CONTENT_TYPE_LENGTH
+ MAX_BODY_LENGTH);
assertTrue(length <= MAX_PACKET_LENGTH);
}
@Test
public void testMessageIdsFitIntoLargeOffer() throws Exception {
testMessageIdsFitIntoOffer(MAX_PACKET_LENGTH);
}
@Test
public void testMessageIdsFitIntoSmallOffer() throws Exception {
testMessageIdsFitIntoOffer(1000);
}
@Test
public void testPropertiesFitIntoTransportUpdate() throws Exception {
// Create the maximum number of properties with the maximum length
TransportProperties p = new TransportProperties();
for(int i = 0; i < MAX_PROPERTIES_PER_TRANSPORT; i++) {
String key = TestUtils.createRandomString(MAX_PROPERTY_LENGTH);
String value = TestUtils.createRandomString(MAX_PROPERTY_LENGTH);
p.put(key, value);
}
// Create a maximum-length transport update
TransportId id = new TransportId(TestUtils.getRandomId());
TransportUpdate u = new TransportUpdate(id, p, Long.MAX_VALUE);
// Serialise the update
ByteArrayOutputStream out = new ByteArrayOutputStream();
PacketWriter writer = packetWriterFactory.createPacketWriter(out, true);
writer.writeTransportUpdate(u);
// Check the size of the serialised transport update
assertTrue(out.size() <= MAX_PACKET_LENGTH);
}
@Test
public void testGroupsFitIntoSubscriptionUpdate() throws Exception {
// Create the maximum number of maximum-length groups
Collection<Group> groups = new ArrayList<Group>();
for(int i = 0; i < MAX_SUBSCRIPTIONS; i++) {
String name = TestUtils.createRandomString(MAX_GROUP_NAME_LENGTH);
groups.add(groupFactory.createGroup(name));
}
// Create a maximum-length subscription update
SubscriptionUpdate u = new SubscriptionUpdate(groups, Long.MAX_VALUE);
// Serialise the update
ByteArrayOutputStream out = new ByteArrayOutputStream();
PacketWriter writer = packetWriterFactory.createPacketWriter(out, true);
writer.writeSubscriptionUpdate(u);
// Check the size of the serialised subscription update
assertTrue(out.size() <= MAX_PACKET_LENGTH);
}
private void testMessageIdsFitIntoAck(int length) throws Exception {
// Create an ack with as many message IDs as possible
ByteArrayOutputStream out = new ByteArrayOutputStream(length);
PacketWriter writer = packetWriterFactory.createPacketWriter(out, true);
int maxMessages = writer.getMaxMessagesForRequest(length);
Collection<MessageId> acked = new ArrayList<MessageId>();
for(int i = 0; i < maxMessages; i++)
acked.add(new MessageId(TestUtils.getRandomId()));
writer.writeAck(new Ack(acked));
// Check the size of the serialised ack
assertTrue(out.size() <= length);
}
private void testMessageIdsFitIntoOffer(int length) throws Exception {
// Create an offer with as many message IDs as possible
ByteArrayOutputStream out = new ByteArrayOutputStream(length);
PacketWriter writer = packetWriterFactory.createPacketWriter(out, true);
int maxMessages = writer.getMaxMessagesForOffer(length);
Collection<MessageId> offered = new ArrayList<MessageId>();
for(int i = 0; i < maxMessages; i++)
offered.add(new MessageId(TestUtils.getRandomId()));
writer.writeOffer(new Offer(offered));
// Check the size of the serialised offer
assertTrue(out.size() <= length);
}
}

View File

@@ -0,0 +1,105 @@
package org.briarproject.messaging;
import static org.junit.Assert.assertArrayEquals;
import java.security.GeneralSecurityException;
import java.util.Random;
import org.briarproject.BriarTestCase;
import org.briarproject.api.FormatException;
import org.briarproject.api.crypto.MessageDigest;
import org.briarproject.api.serial.CopyingConsumer;
import org.briarproject.api.serial.CountingConsumer;
import org.briarproject.api.serial.DigestingConsumer;
import org.junit.Test;
public class ConsumersTest extends BriarTestCase {
@Test
public void testDigestingConsumer() throws Exception {
byte[] data = new byte[1234];
// Generate some random data and digest it
new Random().nextBytes(data);
MessageDigest messageDigest = new TestMessageDigest();
messageDigest.update(data);
byte[] dig = messageDigest.digest();
// Check that feeding a DigestingConsumer generates the same digest
DigestingConsumer dc = new DigestingConsumer(messageDigest);
dc.write(data[0]);
dc.write(data, 1, data.length - 2);
dc.write(data[data.length - 1]);
byte[] dig1 = messageDigest.digest();
assertArrayEquals(dig, dig1);
}
@Test
public void testCountingConsumer() throws Exception {
byte[] data = new byte[1234];
CountingConsumer cc = new CountingConsumer(data.length);
cc.write(data[0]);
cc.write(data, 1, data.length - 2);
cc.write(data[data.length - 1]);
assertEquals(data.length, cc.getCount());
try {
cc.write((byte) 0);
fail();
} catch(FormatException expected) {}
}
@Test
public void testCopyingConsumer() throws Exception {
byte[] data = new byte[1234];
new Random().nextBytes(data);
// Check that a CopyingConsumer creates a faithful copy
CopyingConsumer cc = new CopyingConsumer();
cc.write(data[0]);
cc.write(data, 1, data.length - 2);
cc.write(data[data.length - 1]);
assertArrayEquals(data, cc.getCopy());
}
private static class TestMessageDigest implements MessageDigest {
private final java.security.MessageDigest delegate;
private TestMessageDigest() throws GeneralSecurityException {
delegate = java.security.MessageDigest.getInstance("SHA-384");
}
public byte[] digest() {
return delegate.digest();
}
public byte[] digest(byte[] input) {
return delegate.digest(input);
}
public int digest(byte[] buf, int offset, int len) {
byte[] digest = digest();
len = Math.min(len, digest.length);
System.arraycopy(digest, 0, buf, offset, len);
return len;
}
public int getDigestLength() {
return delegate.getDigestLength();
}
public void reset() {
delegate.reset();
}
public void update(byte input) {
delegate.update(input);
}
public void update(byte[] input) {
delegate.update(input);
}
public void update(byte[] input, int offset, int len) {
delegate.update(input, offset, len);
}
}
}

View File

@@ -0,0 +1,222 @@
package org.briarproject.messaging;
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
import static org.briarproject.api.messaging.Types.ACK;
import static org.briarproject.api.messaging.Types.OFFER;
import static org.briarproject.api.messaging.Types.REQUEST;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import org.briarproject.BriarTestCase;
import org.briarproject.TestUtils;
import org.briarproject.api.FormatException;
import org.briarproject.api.serial.ReaderFactory;
import org.briarproject.api.serial.SerialComponent;
import org.briarproject.api.serial.Writer;
import org.briarproject.api.serial.WriterFactory;
import org.briarproject.serial.SerialModule;
import org.junit.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class PacketReaderImplTest extends BriarTestCase {
// FIXME: This is an integration test, not a unit test
private final SerialComponent serial;
private final ReaderFactory readerFactory;
private final WriterFactory writerFactory;
public PacketReaderImplTest() throws Exception {
Injector i = Guice.createInjector(new SerialModule());
serial = i.getInstance(SerialComponent.class);
readerFactory = i.getInstance(ReaderFactory.class);
writerFactory = i.getInstance(WriterFactory.class);
}
@Test
public void testFormatExceptionIfAckIsTooLarge() throws Exception {
byte[] b = createAck(true);
ByteArrayInputStream in = new ByteArrayInputStream(b);
PacketReaderImpl reader = new PacketReaderImpl(readerFactory, null,
null, in);
try {
reader.readAck();
fail();
} catch(FormatException expected) {}
}
@Test
public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception {
byte[] b = createAck(false);
ByteArrayInputStream in = new ByteArrayInputStream(b);
PacketReaderImpl reader = new PacketReaderImpl(readerFactory, null,
null, in);
reader.readAck();
}
@Test
public void testEmptyAck() throws Exception {
byte[] b = createEmptyAck();
ByteArrayInputStream in = new ByteArrayInputStream(b);
PacketReaderImpl reader = new PacketReaderImpl(readerFactory, null,
null, in);
try {
reader.readAck();
fail();
} catch(FormatException expected) {}
}
@Test
public void testFormatExceptionIfOfferIsTooLarge() throws Exception {
byte[] b = createOffer(true);
ByteArrayInputStream in = new ByteArrayInputStream(b);
PacketReaderImpl reader = new PacketReaderImpl(readerFactory, null,
null, in);
try {
reader.readOffer();
fail();
} catch(FormatException expected) {}
}
@Test
public void testNoFormatExceptionIfOfferIsMaximumSize() throws Exception {
byte[] b = createOffer(false);
ByteArrayInputStream in = new ByteArrayInputStream(b);
PacketReaderImpl reader = new PacketReaderImpl(readerFactory, null,
null, in);
reader.readOffer();
}
@Test
public void testEmptyOffer() throws Exception {
byte[] b = createEmptyOffer();
ByteArrayInputStream in = new ByteArrayInputStream(b);
PacketReaderImpl reader = new PacketReaderImpl(readerFactory, null,
null, in);
try {
reader.readOffer();
fail();
} catch(FormatException expected) {}
}
@Test
public void testFormatExceptionIfRequestIsTooLarge() throws Exception {
byte[] b = createRequest(true);
ByteArrayInputStream in = new ByteArrayInputStream(b);
PacketReaderImpl reader = new PacketReaderImpl(readerFactory, null,
null, in);
try {
reader.readRequest();
fail();
} catch(FormatException expected) {}
}
@Test
public void testNoFormatExceptionIfRequestIsMaximumSize() throws Exception {
byte[] b = createRequest(false);
ByteArrayInputStream in = new ByteArrayInputStream(b);
PacketReaderImpl reader = new PacketReaderImpl(readerFactory, null,
null, in);
reader.readRequest();
}
@Test
public void testEmptyRequest() throws Exception {
byte[] b = createEmptyRequest();
ByteArrayInputStream in = new ByteArrayInputStream(b);
PacketReaderImpl reader = new PacketReaderImpl(readerFactory, null,
null, in);
try {
reader.readRequest();
fail();
} catch(FormatException expected) {}
}
private byte[] createAck(boolean tooBig) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer w = writerFactory.createWriter(out);
w.writeStructStart(ACK);
w.writeListStart();
while(out.size() + serial.getSerialisedUniqueIdLength()
+ serial.getSerialisedListEndLength()
+ serial.getSerialisedStructEndLength()
< MAX_PACKET_LENGTH) {
w.writeBytes(TestUtils.getRandomId());
}
if(tooBig) w.writeBytes(TestUtils.getRandomId());
w.writeListEnd();
w.writeStructEnd();
assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH);
return out.toByteArray();
}
private byte[] createEmptyAck() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer w = writerFactory.createWriter(out);
w.writeStructStart(ACK);
w.writeListStart();
w.writeListEnd();
w.writeStructEnd();
return out.toByteArray();
}
private byte[] createOffer(boolean tooBig) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer w = writerFactory.createWriter(out);
w.writeStructStart(OFFER);
w.writeListStart();
while(out.size() + serial.getSerialisedUniqueIdLength()
+ serial.getSerialisedListEndLength()
+ serial.getSerialisedStructEndLength()
< MAX_PACKET_LENGTH) {
w.writeBytes(TestUtils.getRandomId());
}
if(tooBig) w.writeBytes(TestUtils.getRandomId());
w.writeListEnd();
w.writeStructEnd();
assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH);
return out.toByteArray();
}
private byte[] createEmptyOffer() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer w = writerFactory.createWriter(out);
w.writeStructStart(OFFER);
w.writeListStart();
w.writeListEnd();
w.writeStructEnd();
return out.toByteArray();
}
private byte[] createRequest(boolean tooBig) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer w = writerFactory.createWriter(out);
w.writeStructStart(REQUEST);
w.writeListStart();
while(out.size() + serial.getSerialisedUniqueIdLength()
+ serial.getSerialisedListEndLength()
+ serial.getSerialisedStructEndLength()
< MAX_PACKET_LENGTH) {
w.writeBytes(TestUtils.getRandomId());
}
if(tooBig) w.writeBytes(TestUtils.getRandomId());
w.writeListEnd();
w.writeStructEnd();
assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH);
return out.toByteArray();
}
private byte[] createEmptyRequest() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer w = writerFactory.createWriter(out);
w.writeStructStart(REQUEST);
w.writeListStart();
w.writeListEnd();
w.writeStructEnd();
return out.toByteArray();
}
}

View File

@@ -0,0 +1,209 @@
package org.briarproject.messaging.simplex;
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH;
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
import static org.briarproject.api.transport.TransportConstants.MIN_CONNECTION_LENGTH;
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import org.briarproject.BriarTestCase;
import org.briarproject.TestLifecycleModule;
import org.briarproject.TestUtils;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.UniqueId;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.messaging.Ack;
import org.briarproject.api.messaging.MessageId;
import org.briarproject.api.messaging.PacketWriterFactory;
import org.briarproject.api.transport.ConnectionContext;
import org.briarproject.api.transport.ConnectionRegistry;
import org.briarproject.api.transport.ConnectionWriterFactory;
import org.briarproject.crypto.CryptoModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.messaging.duplex.DuplexMessagingModule;
import org.briarproject.serial.SerialModule;
import org.briarproject.system.SystemModule;
import org.briarproject.transport.TransportModule;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.junit.Test;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
public class OutgoingSimplexConnectionTest extends BriarTestCase {
// FIXME: This is an integration test, not a unit test
private final Mockery context;
private final DatabaseComponent db;
private final ConnectionRegistry connRegistry;
private final ConnectionWriterFactory connWriterFactory;
private final PacketWriterFactory packetWriterFactory;
private final ContactId contactId;
private final MessageId messageId;
private final TransportId transportId;
private final byte[] secret;
public OutgoingSimplexConnectionTest() {
context = new Mockery();
db = context.mock(DatabaseComponent.class);
Module testModule = new AbstractModule() {
public void configure() {
bind(DatabaseComponent.class).toInstance(db);
bind(Executor.class).annotatedWith(
DatabaseExecutor.class).toInstance(
Executors.newCachedThreadPool());
}
};
Injector i = Guice.createInjector(testModule,
new TestLifecycleModule(), new SystemModule(),
new CryptoModule(), new MessagingModule(),
new DuplexMessagingModule(), new SimplexMessagingModule(),
new SerialModule(), new TransportModule());
connRegistry = i.getInstance(ConnectionRegistry.class);
connWriterFactory = i.getInstance(ConnectionWriterFactory.class);
packetWriterFactory = i.getInstance(PacketWriterFactory.class);
contactId = new ContactId(234);
messageId = new MessageId(TestUtils.getRandomId());
transportId = new TransportId(TestUtils.getRandomId());
secret = new byte[32];
new Random().nextBytes(secret);
}
@Test
public void testConnectionTooShort() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
out, MAX_PACKET_LENGTH, Long.MAX_VALUE, true);
ConnectionContext ctx = new ConnectionContext(contactId, transportId,
secret, 0, true);
OutgoingSimplexConnection connection = new OutgoingSimplexConnection(db,
connRegistry, connWriterFactory, packetWriterFactory, ctx,
transport);
connection.write();
// Nothing should have been written
assertEquals(0, out.size());
// The transport should have been disposed with exception == true
assertTrue(transport.getDisposed());
assertTrue(transport.getException());
}
@Test
public void testNothingToSend() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
out, MIN_CONNECTION_LENGTH, Long.MAX_VALUE, true);
ConnectionContext ctx = new ConnectionContext(contactId, transportId,
secret, 0, true);
OutgoingSimplexConnection connection = new OutgoingSimplexConnection(db,
connRegistry, connWriterFactory, packetWriterFactory, ctx,
transport);
context.checking(new Expectations() {{
// No transport acks to send
oneOf(db).generateTransportAcks(contactId);
will(returnValue(null));
// No transport updates to send
oneOf(db).generateTransportUpdates(with(contactId),
with(any(long.class)));
will(returnValue(null));
// No subscription ack to send
oneOf(db).generateSubscriptionAck(contactId);
will(returnValue(null));
// No subscription update to send
oneOf(db).generateSubscriptionUpdate(with(contactId),
with(any(long.class)));
will(returnValue(null));
// No retention ack to send
oneOf(db).generateRetentionAck(contactId);
will(returnValue(null));
// No retention update to send
oneOf(db).generateRetentionUpdate(with(contactId),
with(any(long.class)));
will(returnValue(null));
// No acks to send
oneOf(db).generateAck(with(contactId), with(any(int.class)));
will(returnValue(null));
// No messages to send
oneOf(db).generateBatch(with(contactId), with(any(int.class)),
with(any(long.class)));
will(returnValue(null));
}});
connection.write();
// Nothing should have been written
assertEquals(0, out.size());
// The transport should have been disposed with exception == false
assertTrue(transport.getDisposed());
assertFalse(transport.getException());
context.assertIsSatisfied();
}
@Test
public void testSomethingToSend() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
out, MIN_CONNECTION_LENGTH, Long.MAX_VALUE, true);
ConnectionContext ctx = new ConnectionContext(contactId, transportId,
secret, 0, true);
OutgoingSimplexConnection connection = new OutgoingSimplexConnection(db,
connRegistry, connWriterFactory, packetWriterFactory, ctx,
transport);
final byte[] raw = new byte[1234];
context.checking(new Expectations() {{
// No transport acks to send
oneOf(db).generateTransportAcks(contactId);
will(returnValue(null));
// No transport updates to send
oneOf(db).generateTransportUpdates(with(contactId),
with(any(long.class)));
will(returnValue(null));
// No subscription ack to send
oneOf(db).generateSubscriptionAck(contactId);
will(returnValue(null));
// No subscription update to send
oneOf(db).generateSubscriptionUpdate(with(contactId),
with(any(long.class)));
will(returnValue(null));
// No retention ack to send
oneOf(db).generateRetentionAck(contactId);
will(returnValue(null));
// No retention update to send
oneOf(db).generateRetentionUpdate(with(contactId),
with(any(long.class)));
will(returnValue(null));
// One ack to send
oneOf(db).generateAck(with(contactId), with(any(int.class)));
will(returnValue(new Ack(Arrays.asList(messageId))));
// No more acks
oneOf(db).generateAck(with(contactId), with(any(int.class)));
will(returnValue(null));
// One message to send
oneOf(db).generateBatch(with(contactId), with(any(int.class)),
with(any(long.class)));
will(returnValue(Arrays.asList(raw)));
// No more messages
oneOf(db).generateBatch(with(contactId), with(any(int.class)),
with(any(long.class)));
will(returnValue(null));
}});
connection.write();
// Something should have been written
int overhead = TAG_LENGTH + HEADER_LENGTH + MAC_LENGTH;
assertTrue(out.size() > overhead + UniqueId.LENGTH + raw.length);
// The transport should have been disposed with exception == false
assertTrue(transport.getDisposed());
assertFalse(transport.getException());
context.assertIsSatisfied();
}
}

View File

@@ -0,0 +1,245 @@
package org.briarproject.messaging.simplex;
import static org.briarproject.api.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.api.messaging.MessagingConstants.GROUP_SALT_LENGTH;
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.Random;
import org.briarproject.BriarTestCase;
import org.briarproject.TestDatabaseModule;
import org.briarproject.TestLifecycleModule;
import org.briarproject.TestUtils;
import org.briarproject.api.Author;
import org.briarproject.api.AuthorId;
import org.briarproject.api.ContactId;
import org.briarproject.api.LocalAuthor;
import org.briarproject.api.TransportId;
import org.briarproject.api.crypto.KeyManager;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.MessageAddedEvent;
import org.briarproject.api.messaging.Group;
import org.briarproject.api.messaging.GroupId;
import org.briarproject.api.messaging.Message;
import org.briarproject.api.messaging.MessageFactory;
import org.briarproject.api.messaging.MessageVerifier;
import org.briarproject.api.messaging.PacketReaderFactory;
import org.briarproject.api.messaging.PacketWriterFactory;
import org.briarproject.api.transport.ConnectionContext;
import org.briarproject.api.transport.ConnectionReaderFactory;
import org.briarproject.api.transport.ConnectionRecogniser;
import org.briarproject.api.transport.ConnectionRegistry;
import org.briarproject.api.transport.ConnectionWriterFactory;
import org.briarproject.api.transport.Endpoint;
import org.briarproject.crypto.CryptoModule;
import org.briarproject.db.DatabaseModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.messaging.duplex.DuplexMessagingModule;
import org.briarproject.plugins.ImmediateExecutor;
import org.briarproject.serial.SerialModule;
import org.briarproject.system.SystemModule;
import org.briarproject.transport.TransportModule;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class SimplexMessagingIntegrationTest extends BriarTestCase {
private static final long CLOCK_DIFFERENCE = 60 * 1000;
private static final long LATENCY = 60 * 1000;
private final File testDir = TestUtils.getTestDirectory();
private final File aliceDir = new File(testDir, "alice");
private final File bobDir = new File(testDir, "bob");
private final Group group;
private final TransportId transportId;
private final byte[] initialSecret;
private final long epoch;
private Injector alice, bob;
public SimplexMessagingIntegrationTest() throws Exception {
GroupId groupId = new GroupId(TestUtils.getRandomId());
group = new Group(groupId, "Group", new byte[GROUP_SALT_LENGTH]);
transportId = new TransportId(TestUtils.getRandomId());
// Create matching secrets for Alice and Bob
initialSecret = new byte[32];
new Random().nextBytes(initialSecret);
long rotationPeriod = 2 * CLOCK_DIFFERENCE + LATENCY;
epoch = System.currentTimeMillis() - 2 * rotationPeriod;
}
@Before
public void setUp() {
testDir.mkdirs();
alice = createInjector(aliceDir);
bob = createInjector(bobDir);
}
private Injector createInjector(File dir) {
return Guice.createInjector(new TestDatabaseModule(dir),
new TestLifecycleModule(), new SystemModule(),
new CryptoModule(), new DatabaseModule(), new MessagingModule(),
new DuplexMessagingModule(), new SimplexMessagingModule(),
new SerialModule(), new TransportModule());
}
@Test
public void testInjection() {
DatabaseComponent aliceDb = alice.getInstance(DatabaseComponent.class);
DatabaseComponent bobDb = bob.getInstance(DatabaseComponent.class);
assertFalse(aliceDb == bobDb);
}
@Test
public void testWriteAndRead() throws Exception {
read(write());
}
private byte[] write() throws Exception {
// Open Alice's database
DatabaseComponent db = alice.getInstance(DatabaseComponent.class);
assertFalse(db.open());
// Start Alice's key manager
KeyManager km = alice.getInstance(KeyManager.class);
km.start();
// Add a local pseudonym for Alice
AuthorId aliceId = new AuthorId(TestUtils.getRandomId());
LocalAuthor aliceAuthor = new LocalAuthor(aliceId, "Alice",
new byte[MAX_PUBLIC_KEY_LENGTH], new byte[100]);
db.addLocalAuthor(aliceAuthor);
// Add Bob as a contact
AuthorId bobId = new AuthorId(TestUtils.getRandomId());
Author bobAuthor = new Author(bobId, "Bob",
new byte[MAX_PUBLIC_KEY_LENGTH]);
ContactId contactId = db.addContact(bobAuthor, aliceId);
// Add the inbox group
db.addGroup(group);
db.setInboxGroup(contactId, group);
// Add the transport and the endpoint
db.addTransport(transportId, LATENCY);
Endpoint ep = new Endpoint(contactId, transportId, epoch, true);
db.addEndpoint(ep);
km.endpointAdded(ep, LATENCY, initialSecret.clone());
// Send Bob a message
String contentType = "text/plain";
long timestamp = System.currentTimeMillis();
byte[] body = "Hi Bob!".getBytes("UTF-8");
MessageFactory messageFactory = alice.getInstance(MessageFactory.class);
Message message = messageFactory.createAnonymousMessage(null, group,
contentType, timestamp, body);
db.addLocalMessage(message);
// Create an outgoing simplex connection
ByteArrayOutputStream out = new ByteArrayOutputStream();
ConnectionRegistry connRegistry =
alice.getInstance(ConnectionRegistry.class);
ConnectionWriterFactory connWriterFactory =
alice.getInstance(ConnectionWriterFactory.class);
PacketWriterFactory packetWriterFactory =
alice.getInstance(PacketWriterFactory.class);
TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
out, Long.MAX_VALUE, Long.MAX_VALUE, false);
ConnectionContext ctx = km.getConnectionContext(contactId, transportId);
assertNotNull(ctx);
OutgoingSimplexConnection simplex = new OutgoingSimplexConnection(db,
connRegistry, connWriterFactory, packetWriterFactory, ctx,
transport);
// Write whatever needs to be written
simplex.write();
assertTrue(transport.getDisposed());
assertFalse(transport.getException());
// Clean up
km.stop();
db.close();
// Return the contents of the simplex connection
return out.toByteArray();
}
private void read(byte[] b) throws Exception {
// Open Bob's database
DatabaseComponent db = bob.getInstance(DatabaseComponent.class);
assertFalse(db.open());
// Start Bob's key manager
KeyManager km = bob.getInstance(KeyManager.class);
km.start();
// Add a local pseudonym for Bob
AuthorId bobId = new AuthorId(TestUtils.getRandomId());
LocalAuthor bobAuthor = new LocalAuthor(bobId, "Bob",
new byte[MAX_PUBLIC_KEY_LENGTH], new byte[100]);
db.addLocalAuthor(bobAuthor);
// Add Alice as a contact
AuthorId aliceId = new AuthorId(TestUtils.getRandomId());
Author aliceAuthor = new Author(aliceId, "Alice",
new byte[MAX_PUBLIC_KEY_LENGTH]);
ContactId contactId = db.addContact(aliceAuthor, bobId);
// Add the inbox group
db.addGroup(group);
db.setInboxGroup(contactId, group);
// Add the transport and the endpoint
db.addTransport(transportId, LATENCY);
Endpoint ep = new Endpoint(contactId, transportId, epoch, false);
db.addEndpoint(ep);
km.endpointAdded(ep, LATENCY, initialSecret.clone());
// Set up a database listener
MessageListener listener = new MessageListener();
db.addListener(listener);
// Create a connection recogniser and recognise the connection
ByteArrayInputStream in = new ByteArrayInputStream(b);
ConnectionRecogniser rec = bob.getInstance(ConnectionRecogniser.class);
byte[] tag = new byte[TAG_LENGTH];
int read = in.read(tag);
assertEquals(tag.length, read);
ConnectionContext ctx = rec.acceptConnection(transportId, tag);
assertNotNull(ctx);
// Create an incoming simplex connection
MessageVerifier messageVerifier =
bob.getInstance(MessageVerifier.class);
ConnectionRegistry connRegistry =
bob.getInstance(ConnectionRegistry.class);
ConnectionReaderFactory connWriterFactory =
bob.getInstance(ConnectionReaderFactory.class);
PacketReaderFactory packetWriterFactory =
bob.getInstance(PacketReaderFactory.class);
TestSimplexTransportReader transport =
new TestSimplexTransportReader(in);
IncomingSimplexConnection simplex = new IncomingSimplexConnection(
new ImmediateExecutor(), new ImmediateExecutor(),
messageVerifier, db, connRegistry, connWriterFactory,
packetWriterFactory, ctx, transport);
// No messages should have been added yet
assertFalse(listener.messageAdded);
// Read whatever needs to be read
simplex.read();
assertTrue(transport.getDisposed());
assertFalse(transport.getException());
assertTrue(transport.getRecognised());
// The private message from Alice should have been added
assertTrue(listener.messageAdded);
// Clean up
km.stop();
db.close();
}
@After
public void tearDown() {
TestUtils.deleteTestDirectory(testDir);
}
private static class MessageListener implements EventListener {
private boolean messageAdded = false;
public void eventOccurred(Event e) {
if(e instanceof MessageAddedEvent) messageAdded = true;
}
}
}

View File

@@ -0,0 +1,45 @@
package org.briarproject.messaging.simplex;
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
import java.io.InputStream;
import org.briarproject.api.plugins.simplex.SimplexTransportReader;
class TestSimplexTransportReader implements SimplexTransportReader {
private final InputStream in;
private boolean disposed = false, exception = false, recognised = false;
TestSimplexTransportReader(InputStream in) {
this.in = in;
}
public int getMaxFrameLength() {
return MAX_FRAME_LENGTH;
}
public InputStream getInputStream() {
return in;
}
public void dispose(boolean exception, boolean recognised) {
assert !disposed;
disposed = true;
this.exception = exception;
this.recognised = recognised;
}
boolean getDisposed() {
return disposed;
}
boolean getException() {
return exception;
}
boolean getRecognised() {
return recognised;
}
}

View File

@@ -0,0 +1,59 @@
package org.briarproject.messaging.simplex;
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import org.briarproject.api.plugins.simplex.SimplexTransportWriter;
class TestSimplexTransportWriter implements SimplexTransportWriter {
private final ByteArrayOutputStream out;
private final long capacity, maxLatency;
private final boolean flush;
private boolean disposed = false, exception = false;
TestSimplexTransportWriter(ByteArrayOutputStream out, long capacity,
long maxLatency, boolean flush) {
this.out = out;
this.capacity = capacity;
this.maxLatency = maxLatency;
this.flush = flush;
}
public long getCapacity() {
return capacity;
}
public int getMaxFrameLength() {
return MAX_FRAME_LENGTH;
}
public long getMaxLatency() {
return maxLatency;
}
public OutputStream getOutputStream() {
return out;
}
public boolean shouldFlush() {
return flush;
}
public void dispose(boolean exception) {
assert !disposed;
disposed = true;
this.exception = exception;
}
boolean getDisposed() {
return disposed;
}
boolean getException() {
return exception;
}
}