From f2d80825bc3b604afb2737ba2eb066efd40cf600 Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Fri, 21 Oct 2011 18:25:25 +0100 Subject: [PATCH] Separated the subject line from the message body. --- api/net/sf/briar/api/protocol/Message.java | 6 ++++ .../sf/briar/api/protocol/MessageEncoder.java | 17 ++++----- .../sf/briar/protocol/MessageEncoderImpl.java | 33 ++++++++++------- .../net/sf/briar/protocol/MessageImpl.java | 8 ++++- .../net/sf/briar/protocol/MessageReader.java | 5 ++- .../net/sf/briar/ProtocolIntegrationTest.java | 11 +++--- .../sf/briar/db/DatabaseComponentTest.java | 10 +++--- test/net/sf/briar/db/H2DatabaseTest.java | 36 ++++++++++--------- test/net/sf/briar/db/TestMessage.java | 8 ++++- .../briar/protocol/ProtocolReadWriteTest.java | 3 +- .../briar/protocol/writers/ConstantsTest.java | 9 +++-- .../batch/BatchConnectionReadWriteTest.java | 3 +- 12 files changed, 95 insertions(+), 54 deletions(-) diff --git a/api/net/sf/briar/api/protocol/Message.java b/api/net/sf/briar/api/protocol/Message.java index 5af513d283..6b056700aa 100644 --- a/api/net/sf/briar/api/protocol/Message.java +++ b/api/net/sf/briar/api/protocol/Message.java @@ -10,6 +10,9 @@ public interface Message { static final int MAX_BODY_LENGTH = ProtocolConstants.MAX_PACKET_LENGTH - 1024; + /** The maximum length of a subject line in UTF-8 bytes. */ + static final int MAX_SUBJECT_LENGTH = 100; + /** The maximum length of a signature in bytes. */ static final int MAX_SIGNATURE_LENGTH = 100; @@ -31,6 +34,9 @@ public interface Message { /** Returns the message's author. */ AuthorId getAuthor(); + /** Returns the message's subject line. */ + String getSubject(); + /** Returns the timestamp created by the message's author. */ long getTimestamp(); diff --git a/api/net/sf/briar/api/protocol/MessageEncoder.java b/api/net/sf/briar/api/protocol/MessageEncoder.java index e1322cbedc..d01f5f0a9d 100644 --- a/api/net/sf/briar/api/protocol/MessageEncoder.java +++ b/api/net/sf/briar/api/protocol/MessageEncoder.java @@ -7,24 +7,25 @@ import java.security.PrivateKey; public interface MessageEncoder { /** Encodes a private message. */ - Message encodeMessage(MessageId parent, byte[] body) throws IOException, - GeneralSecurityException; + Message encodeMessage(MessageId parent, String subject, byte[] body) + throws IOException, GeneralSecurityException; /** Encodes an anonymous message to an unrestricted group. */ - Message encodeMessage(MessageId parent, Group group, byte[] body) - throws IOException, GeneralSecurityException; + Message encodeMessage(MessageId parent, Group group, String subject, + byte[] body) throws IOException, GeneralSecurityException; /** Encodes an anonymous message to a restricted group. */ Message encodeMessage(MessageId parent, Group group, PrivateKey groupKey, - byte[] body) throws IOException, GeneralSecurityException; + String subject, byte[] body) throws IOException, + GeneralSecurityException; /** Encodes a pseudonymous message to an unrestricted group. */ Message encodeMessage(MessageId parent, Group group, Author author, - PrivateKey authorKey, byte[] body) throws IOException, - GeneralSecurityException; + PrivateKey authorKey, String subject, byte[] body) + throws IOException, GeneralSecurityException; /** Encode a pseudonymous message to a restricted group. */ Message encodeMessage(MessageId parent, Group group, PrivateKey groupKey, - Author author, PrivateKey authorKey, byte[] body) + Author author, PrivateKey authorKey, String subject, byte[] body) throws IOException, GeneralSecurityException; } diff --git a/components/net/sf/briar/protocol/MessageEncoderImpl.java b/components/net/sf/briar/protocol/MessageEncoderImpl.java index acf1aeebf0..39ab3b47f3 100644 --- a/components/net/sf/briar/protocol/MessageEncoderImpl.java +++ b/components/net/sf/briar/protocol/MessageEncoderImpl.java @@ -39,37 +39,42 @@ class MessageEncoderImpl implements MessageEncoder { this.writerFactory = writerFactory; } - public Message encodeMessage(MessageId parent, byte[] body) + public Message encodeMessage(MessageId parent, String subject, byte[] body) throws IOException, GeneralSecurityException { - return encodeMessage(parent, null, null, null, null, body); + return encodeMessage(parent, null, null, null, null, subject, body); } - public Message encodeMessage(MessageId parent, Group group, byte[] body) - throws IOException, GeneralSecurityException { - return encodeMessage(parent, group, null, null, null, body); + public Message encodeMessage(MessageId parent, Group group, String subject, + byte[] body) throws IOException, GeneralSecurityException { + return encodeMessage(parent, group, null, null, null, subject, body); } public Message encodeMessage(MessageId parent, Group group, - PrivateKey groupKey, byte[] body) throws IOException, - GeneralSecurityException { - return encodeMessage(parent, group, groupKey, null, null, body); + PrivateKey groupKey, String subject, byte[] body) + throws IOException, GeneralSecurityException { + return encodeMessage(parent, group, groupKey, null, null, subject, + body); } public Message encodeMessage(MessageId parent, Group group, Author author, - PrivateKey authorKey, byte[] body) throws IOException, - GeneralSecurityException { - return encodeMessage(parent, group, null, author, authorKey, body); + PrivateKey authorKey, String subject, byte[] body) + throws IOException, GeneralSecurityException { + return encodeMessage(parent, group, null, author, authorKey, subject, + body); } public Message encodeMessage(MessageId parent, Group group, PrivateKey groupKey, Author author, PrivateKey authorKey, - byte[] body) throws IOException, GeneralSecurityException { + String subject, byte[] body) throws IOException, + GeneralSecurityException { if((author == null) != (authorKey == null)) throw new IllegalArgumentException(); if((group == null || group.getPublicKey() == null) != (groupKey == null)) throw new IllegalArgumentException(); + if(subject.getBytes("UTF-8").length > Message.MAX_SUBJECT_LENGTH) + throw new IllegalArgumentException(); if(body.length > Message.MAX_BODY_LENGTH) throw new IllegalArgumentException(); @@ -98,6 +103,7 @@ class MessageEncoderImpl implements MessageEncoder { else group.writeTo(w); if(author == null) w.writeNull(); else author.writeTo(w); + w.writeString(subject); long timestamp = System.currentTimeMillis(); w.writeInt64(timestamp); byte[] salt = new byte[Message.SALT_LENGTH]; @@ -130,6 +136,7 @@ class MessageEncoderImpl implements MessageEncoder { MessageId id = new MessageId(messageDigest.digest()); GroupId groupId = group == null ? null : group.getId(); AuthorId authorId = author == null ? null : author.getId(); - return new MessageImpl(id, parent, groupId, authorId, timestamp, raw); + return new MessageImpl(id, parent, groupId, authorId, subject, + timestamp, raw); } } diff --git a/components/net/sf/briar/protocol/MessageImpl.java b/components/net/sf/briar/protocol/MessageImpl.java index a8360a7ed8..e8e54e1eb4 100644 --- a/components/net/sf/briar/protocol/MessageImpl.java +++ b/components/net/sf/briar/protocol/MessageImpl.java @@ -11,15 +11,17 @@ class MessageImpl implements Message { private final MessageId id, parent; private final GroupId group; private final AuthorId author; + private final String subject; private final long timestamp; private final byte[] raw; public MessageImpl(MessageId id, MessageId parent, GroupId group, - AuthorId author, long timestamp, byte[] raw) { + AuthorId author, String subject, long timestamp, byte[] raw) { this.id = id; this.parent = parent; this.group = group; this.author = author; + this.subject = subject; this.timestamp = timestamp; this.raw = raw; } @@ -40,6 +42,10 @@ class MessageImpl implements Message { return author; } + public String getSubject() { + return subject; + } + public long getTimestamp() { return timestamp; } diff --git a/components/net/sf/briar/protocol/MessageReader.java b/components/net/sf/briar/protocol/MessageReader.java index 30339c2453..52e398a1c4 100644 --- a/components/net/sf/briar/protocol/MessageReader.java +++ b/components/net/sf/briar/protocol/MessageReader.java @@ -76,6 +76,8 @@ class MessageReader implements ObjectReader<Message> { author = r.readUserDefined(Types.AUTHOR, Author.class); r.removeObjectReader(Types.AUTHOR); } + // Read the subject + String subject = r.readString(Message.MAX_SUBJECT_LENGTH); // Read the timestamp long timestamp = r.readInt64(); if(timestamp < 0L) throw new FormatException(); @@ -128,6 +130,7 @@ class MessageReader implements ObjectReader<Message> { MessageId id = new MessageId(messageDigest.digest()); GroupId groupId = group == null ? null : group.getId(); AuthorId authorId = author == null ? null : author.getId(); - return new MessageImpl(id, parent, groupId, authorId, timestamp, raw); + return new MessageImpl(id, parent, groupId, authorId, subject, + timestamp, raw); } } diff --git a/test/net/sf/briar/ProtocolIntegrationTest.java b/test/net/sf/briar/ProtocolIntegrationTest.java index 2ce0a1077c..e57d649f3c 100644 --- a/test/net/sf/briar/ProtocolIntegrationTest.java +++ b/test/net/sf/briar/ProtocolIntegrationTest.java @@ -75,6 +75,7 @@ public class ProtocolIntegrationTest extends TestCase { private final Group group, group1; private final Message message, message1, message2, message3; private final String authorName = "Alice"; + private final String subject = "Hello"; private final String messageBody = "Hello world"; private final Map<TransportId, TransportProperties> transports; @@ -108,15 +109,17 @@ public class ProtocolIntegrationTest extends TestCase { authorKeyPair.getPublic().getEncoded()); // Create two messages to each group: one anonymous, one pseudonymous MessageEncoder messageEncoder = i.getInstance(MessageEncoder.class); - message = messageEncoder.encodeMessage(null, group, + message = messageEncoder.encodeMessage(null, group, subject, messageBody.getBytes("UTF-8")); message1 = messageEncoder.encodeMessage(null, group1, - groupKeyPair.getPrivate(), messageBody.getBytes("UTF-8")); + groupKeyPair.getPrivate(), subject, + messageBody.getBytes("UTF-8")); message2 = messageEncoder.encodeMessage(null, group, author, - authorKeyPair.getPrivate(), messageBody.getBytes("UTF-8")); + authorKeyPair.getPrivate(), subject, + messageBody.getBytes("UTF-8")); message3 = messageEncoder.encodeMessage(null, group1, groupKeyPair.getPrivate(), author, authorKeyPair.getPrivate(), - messageBody.getBytes("UTF-8")); + subject, messageBody.getBytes("UTF-8")); TransportProperties p = new TransportProperties(Collections.singletonMap("bar", "baz")); transports = Collections.singletonMap(transportId, p); diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java index fecd3f4183..bc846980bd 100644 --- a/test/net/sf/briar/db/DatabaseComponentTest.java +++ b/test/net/sf/briar/db/DatabaseComponentTest.java @@ -52,6 +52,7 @@ public abstract class DatabaseComponentTest extends TestCase { protected final ContactId contactId; protected final GroupId groupId; protected final MessageId messageId, parentId; + private final String subject; private final long timestamp; private final int size; private final byte[] raw; @@ -70,13 +71,14 @@ public abstract class DatabaseComponentTest extends TestCase { groupId = new GroupId(TestUtils.getRandomId()); messageId = new MessageId(TestUtils.getRandomId()); parentId = new MessageId(TestUtils.getRandomId()); + subject = "Foo"; timestamp = System.currentTimeMillis(); size = 1234; raw = new byte[size]; - message = - new TestMessage(messageId, null, groupId, authorId, timestamp, raw); - privateMessage = - new TestMessage(messageId, null, null, null, timestamp, raw); + message = new TestMessage(messageId, null, groupId, authorId, subject, + timestamp, raw); + privateMessage = new TestMessage(messageId, null, null, null, subject, + timestamp, raw); group = new TestGroup(groupId, "The really exciting group", null); transportId = new TransportId(123); TransportProperties p = diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java index f293677ef6..9f26ce7528 100644 --- a/test/net/sf/briar/db/H2DatabaseTest.java +++ b/test/net/sf/briar/db/H2DatabaseTest.java @@ -66,6 +66,7 @@ public class H2DatabaseTest extends TestCase { private final ContactId contactId; private final GroupId groupId; private final MessageId messageId, privateMessageId; + private final String subject; private final long timestamp; private final int size; private final byte[] raw; @@ -91,14 +92,15 @@ public class H2DatabaseTest extends TestCase { groupId = new GroupId(TestUtils.getRandomId()); messageId = new MessageId(TestUtils.getRandomId()); privateMessageId = new MessageId(TestUtils.getRandomId()); + subject = "Foo"; timestamp = System.currentTimeMillis(); size = 1234; raw = new byte[size]; random.nextBytes(raw); - message = - new TestMessage(messageId, null, groupId, authorId, timestamp, raw); - privateMessage = - new TestMessage(privateMessageId, null, null, null, timestamp, raw); + message = new TestMessage(messageId, null, groupId, authorId, subject, + timestamp, raw); + privateMessage = new TestMessage(privateMessageId, null, null, null, + subject, timestamp, raw); group = groupFactory.createGroup(groupId, "Group name", null); transportId = new TransportId(0); properties = new TransportProperties( @@ -797,7 +799,7 @@ public class H2DatabaseTest extends TestCase { AuthorId authorId1 = new AuthorId(TestUtils.getRandomId()); MessageId messageId1 = new MessageId(TestUtils.getRandomId()); Message message1 = new TestMessage(messageId1, null, groupId, authorId1, - timestamp, raw); + subject, timestamp, raw); Database<Connection> db = open(false); Connection txn = db.startTransaction(); @@ -830,12 +832,12 @@ public class H2DatabaseTest extends TestCase { Group group1 = groupFactory.createGroup(groupId1, "Another group name", null); Message child1 = new TestMessage(childId1, messageId, groupId, - authorId, timestamp, raw); + authorId, subject, timestamp, raw); Message child2 = new TestMessage(childId2, messageId, groupId, - authorId, timestamp, raw); + authorId, subject, timestamp, raw); // The third child is in a different group Message child3 = new TestMessage(childId3, messageId, groupId1, - authorId, timestamp, raw); + authorId, subject, timestamp, raw); Database<Connection> db = open(false); Connection txn = db.startTransaction(); @@ -866,7 +868,7 @@ public class H2DatabaseTest extends TestCase { public void testGetOldMessages() throws Exception { MessageId messageId1 = new MessageId(TestUtils.getRandomId()); Message message1 = new TestMessage(messageId1, null, groupId, authorId, - timestamp + 1000, raw); + subject, timestamp + 1000, raw); Database<Connection> db = open(false); Connection txn = db.startTransaction(); @@ -897,7 +899,7 @@ public class H2DatabaseTest extends TestCase { byte[] largeBody = new byte[ONE_MEGABYTE]; for(int i = 0; i < largeBody.length; i++) largeBody[i] = (byte) i; Message message1 = new TestMessage(messageId, null, groupId, authorId, - timestamp, largeBody); + subject, timestamp, largeBody); Database<Connection> db = open(false); // Sanity check: there should be enough space on disk for this test @@ -1463,7 +1465,7 @@ public class H2DatabaseTest extends TestCase { // A message with no parent should return null MessageId childId = new MessageId(TestUtils.getRandomId()); - Message child = new TestMessage(childId, null, groupId, null, + Message child = new TestMessage(childId, null, groupId, null, subject, timestamp, raw); db.addGroupMessage(txn, child); assertTrue(db.containsMessage(txn, childId)); @@ -1485,7 +1487,7 @@ public class H2DatabaseTest extends TestCase { MessageId childId = new MessageId(TestUtils.getRandomId()); MessageId parentId = new MessageId(TestUtils.getRandomId()); Message child = new TestMessage(childId, parentId, groupId, null, - timestamp, raw); + subject, timestamp, raw); db.addGroupMessage(txn, child); assertTrue(db.containsMessage(txn, childId)); assertFalse(db.containsMessage(txn, parentId)); @@ -1511,9 +1513,9 @@ public class H2DatabaseTest extends TestCase { MessageId childId = new MessageId(TestUtils.getRandomId()); MessageId parentId = new MessageId(TestUtils.getRandomId()); Message child = new TestMessage(childId, parentId, groupId, null, - timestamp, raw); + subject, timestamp, raw); Message parent = new TestMessage(parentId, null, groupId1, null, - timestamp, raw); + subject, timestamp, raw); db.addGroupMessage(txn, child); db.addGroupMessage(txn, parent); assertTrue(db.containsMessage(txn, childId)); @@ -1537,7 +1539,7 @@ public class H2DatabaseTest extends TestCase { // A message with a private parent should return null MessageId childId = new MessageId(TestUtils.getRandomId()); Message child = new TestMessage(childId, privateMessageId, groupId, - null, timestamp, raw); + null, subject, timestamp, raw); db.addGroupMessage(txn, child); db.addPrivateMessage(txn, privateMessage, contactId); assertTrue(db.containsMessage(txn, childId)); @@ -1561,9 +1563,9 @@ public class H2DatabaseTest extends TestCase { MessageId childId = new MessageId(TestUtils.getRandomId()); MessageId parentId = new MessageId(TestUtils.getRandomId()); Message child = new TestMessage(childId, parentId, groupId, null, - timestamp, raw); + subject, timestamp, raw); Message parent = new TestMessage(parentId, null, groupId, null, - timestamp, raw); + subject, timestamp, raw); db.addGroupMessage(txn, child); db.addGroupMessage(txn, parent); assertTrue(db.containsMessage(txn, childId)); diff --git a/test/net/sf/briar/db/TestMessage.java b/test/net/sf/briar/db/TestMessage.java index 6b0b017815..c118dd7157 100644 --- a/test/net/sf/briar/db/TestMessage.java +++ b/test/net/sf/briar/db/TestMessage.java @@ -10,15 +10,17 @@ class TestMessage implements Message { private final MessageId id, parent; private final GroupId group; private final AuthorId author; + private final String subject; private final long timestamp; private final byte[] raw; public TestMessage(MessageId id, MessageId parent, GroupId group, - AuthorId author, long timestamp, byte[] raw) { + AuthorId author, String subject, long timestamp, byte[] raw) { this.id = id; this.parent = parent; this.group = group; this.author = author; + this.subject = subject; this.timestamp = timestamp; this.raw = raw; } @@ -39,6 +41,10 @@ class TestMessage implements Message { return author; } + public String getSubject() { + return subject; + } + public long getTimestamp() { return timestamp; } diff --git a/test/net/sf/briar/protocol/ProtocolReadWriteTest.java b/test/net/sf/briar/protocol/ProtocolReadWriteTest.java index f98a61504c..43598bc483 100644 --- a/test/net/sf/briar/protocol/ProtocolReadWriteTest.java +++ b/test/net/sf/briar/protocol/ProtocolReadWriteTest.java @@ -46,6 +46,7 @@ public class ProtocolReadWriteTest extends TestCase { private final BatchId batchId; private final Group group; private final Message message; + private final String subject = "Hello"; private final String messageBody = "Hello world"; private final BitSet bitSet; private final Map<Group, Long> subscriptions; @@ -64,7 +65,7 @@ public class ProtocolReadWriteTest extends TestCase { GroupFactory groupFactory = i.getInstance(GroupFactory.class); group = groupFactory.createGroup("Unrestricted group", null); MessageEncoder messageEncoder = i.getInstance(MessageEncoder.class); - message = messageEncoder.encodeMessage(null, group, + message = messageEncoder.encodeMessage(null, group, subject, messageBody.getBytes("UTF-8")); bitSet = new BitSet(); bitSet.set(3); diff --git a/test/net/sf/briar/protocol/writers/ConstantsTest.java b/test/net/sf/briar/protocol/writers/ConstantsTest.java index 84c30ebc0d..694cc5a3a8 100644 --- a/test/net/sf/briar/protocol/writers/ConstantsTest.java +++ b/test/net/sf/briar/protocol/writers/ConstantsTest.java @@ -104,9 +104,10 @@ public class ConstantsTest extends TestCase { // Create a maximum-length message PrivateKey groupPrivate = crypto.generateKeyPair().getPrivate(); PrivateKey authorPrivate = crypto.generateKeyPair().getPrivate(); + String subject = createRandomString(Message.MAX_SUBJECT_LENGTH); byte[] body = new byte[Message.MAX_BODY_LENGTH]; Message message = messageEncoder.encodeMessage(null, group, - groupPrivate, author, authorPrivate, body); + groupPrivate, author, authorPrivate, subject, body); // Add the message to a batch ByteArrayOutputStream out = new ByteArrayOutputStream( ProtocolConstants.MAX_PACKET_LENGTH); @@ -216,12 +217,14 @@ public class ConstantsTest extends TestCase { assertTrue(out.size() <= ProtocolConstants.MAX_PACKET_LENGTH); } - private static String createRandomString(int length) { + private static String createRandomString(int length) throws Exception { StringBuilder s = new StringBuilder(length); for(int i = 0; i < length; i++) { int digit = (int) (Math.random() * 10); s.append((char) ('0' + digit)); } - return s.toString(); + String string = s.toString(); + assertEquals(length, string.getBytes("UTF-8").length); + return string; } } diff --git a/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java b/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java index df42455298..b6d0ab5e80 100644 --- a/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java +++ b/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java @@ -97,9 +97,10 @@ public class BatchConnectionReadWriteTest extends TestCase { db.open(false); // Add Bob as a contact and send him a message ContactId contactId = db.addContact(transports, aliceSecret); + String subject = "Hello"; byte[] messageBody = "Hi Bob!".getBytes("UTF-8"); MessageEncoder encoder = alice.getInstance(MessageEncoder.class); - Message message = encoder.encodeMessage(null, messageBody); + Message message = encoder.encodeMessage(null, subject, messageBody); db.addLocalPrivateMessage(message, contactId); // Create an outgoing batch connection ByteArrayOutputStream out = new ByteArrayOutputStream(); -- GitLab