mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 02:39:05 +01:00
Separated the subject line from the message body.
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user