Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package org.briarproject.privategroup.invitation;
import org.briarproject.ValidatorTestCase;
import org.briarproject.api.FormatException;
import org.briarproject.api.UniqueId;
import org.briarproject.api.clients.BdfMessageContext;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfEntry;
import org.briarproject.api.data.BdfList;
import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.privategroup.PrivateGroup;
import org.briarproject.api.privategroup.PrivateGroupFactory;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.jmock.Expectations;
import org.junit.Test;
import java.security.GeneralSecurityException;
import static org.briarproject.TestUtils.getRandomBytes;
import static org.briarproject.TestUtils.getRandomId;
import static org.briarproject.TestUtils.getRandomString;
import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
import static org.briarproject.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH;
import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_MSG_LENGTH;
import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH;
import static org.briarproject.api.privategroup.invitation.GroupInvitationFactory.SIGNING_LABEL_INVITE;
import static org.briarproject.privategroup.invitation.MessageType.ABORT;
import static org.briarproject.privategroup.invitation.MessageType.INVITE;
import static org.briarproject.privategroup.invitation.MessageType.JOIN;
import static org.briarproject.privategroup.invitation.MessageType.LEAVE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class GroupInvitationValidatorTest extends ValidatorTestCase {
private final PrivateGroupFactory privateGroupFactory =
context.mock(PrivateGroupFactory.class);
private final MessageEncoder messageEncoder =
context.mock(MessageEncoder.class);
private final String groupName = getRandomString(MAX_GROUP_NAME_LENGTH);
private final String creatorName = getRandomString(MAX_AUTHOR_NAME_LENGTH);
private final byte[] creatorKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
private final Author creator =
new Author(new AuthorId(getRandomId()), creatorName, creatorKey);
private final byte[] salt = getRandomBytes(GROUP_SALT_LENGTH);
private final PrivateGroup privateGroup =
new PrivateGroup(group, groupName, creator, salt);
private final String inviteText =
getRandomString(MAX_GROUP_INVITATION_MSG_LENGTH);
private final byte[] signature = getRandomBytes(MAX_SIGNATURE_LENGTH);
private final BdfDictionary meta =
BdfDictionary.of(new BdfEntry("meta", "data"));
private final MessageId previousMessageId = new MessageId(getRandomId());
private final GroupInvitationValidator validator =
new GroupInvitationValidator(clientHelper, metadataEncoder,
clock, authorFactory, privateGroupFactory, messageEncoder);
@Test(expected = FormatException.class)
public void testRejectsTooShortInviteMessage() throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsTooLongInviteMessage() throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, salt, inviteText, signature, "");
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooShortGroupName()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), "", creatorName,
creatorKey, salt, inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooLongGroupName()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(),
getRandomString(MAX_GROUP_NAME_LENGTH + 1), creatorName,
creatorKey, salt, inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithNullGroupName()
BdfList body = BdfList.of(INVITE.getValue(), null, creatorName,
creatorKey, salt, inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithNonStringGroupName()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), getRandomBytes(5),
creatorName, creatorKey, salt, inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooShortCreatorName()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, "", creatorKey,
salt, inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooLongCreatorName()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName,
getRandomString(MAX_AUTHOR_NAME_LENGTH + 1), creatorKey, salt,
inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithNullCreatorName()
BdfList body = BdfList.of(INVITE.getValue(), groupName, null,
creatorKey, salt, inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithNonStringCreatorName()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName,
getRandomBytes(5), creatorKey, salt, inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooShortCreatorKey()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
new byte[0], salt, inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooLongCreatorKey()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1), salt, inviteText,
signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithNullCreatorKey()
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
null, salt, inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithNonRawCreatorKey()
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
"not raw", salt, inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooShortGroupSalt()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, getRandomBytes(GROUP_SALT_LENGTH - 1), inviteText,
signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooLongGroupSalt()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, getRandomBytes(GROUP_SALT_LENGTH + 1), inviteText,
signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithNullGroupSalt()
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, null, inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithNonRawGroupSalt()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, "not raw", inviteText, signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooShortContent() throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, salt, "", signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooLongContent() throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, salt,
getRandomString(MAX_GROUP_INVITATION_MSG_LENGTH + 1),
signature);
validator.validateMessage(message, group, body);
}
@Test
public void testAcceptsInviteMessageWithNullContent() throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, salt, null, signature);
expectInviteMessage(false);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithNonStringContent()
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, salt, getRandomBytes(5), signature);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooShortSignature()
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, salt, inviteText, new byte[0]);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithTooLongSignature()
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, salt, inviteText,
getRandomBytes(MAX_SIGNATURE_LENGTH + 1));
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithNullSignature()
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, salt, inviteText, null);
validator.validateMessage(message, group, body);
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithNonRawSignature()
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, salt, inviteText, "not raw");
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsInviteMessageWithInvalidSignature()
throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
expectInviteMessage(true);
validator.validateMessage(message, group, body);
public void testAcceptsValidInviteMessage() throws Exception {
BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName,
creatorKey, salt, inviteText, signature);
expectInviteMessage(false);
validator.validateMessage(message, group, body);
assertTrue(messageContext.getDependencies().isEmpty());
assertEquals(meta, messageContext.getDictionary());
}
private void expectInviteMessage(final boolean exception) throws Exception {
final BdfList signed = BdfList.of(message.getTimestamp(),
message.getGroupId(), privateGroup.getId());
context.checking(new Expectations() {{
oneOf(authorFactory).createAuthor(creatorName, creatorKey);
will(returnValue(creator));
oneOf(privateGroupFactory).createPrivateGroup(groupName, creator,
salt);
will(returnValue(privateGroup));
oneOf(clientHelper).verifySignature(SIGNING_LABEL_INVITE, signature,
creatorKey, signed);
if (exception) {
will(throwException(new GeneralSecurityException()));
} else {
oneOf(messageEncoder).encodeMetadata(INVITE,
message.getGroupId(), message.getTimestamp(), false,
false, false, false);
will(returnValue(meta));
}
}});
}
// JOIN Message
@Test(expected = FormatException.class)
public void testRejectsTooShortJoinMessage() throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId());
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsTooLongJoinMessage() throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(),
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsJoinMessageWithTooShortGroupId() throws Exception {
BdfList body = BdfList.of(JOIN.getValue(),
getRandomBytes(GroupId.LENGTH - 1), previousMessageId);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsJoinMessageWithTooLongGroupId() throws Exception {
BdfList body = BdfList.of(JOIN.getValue(),
getRandomBytes(GroupId.LENGTH + 1), previousMessageId);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsJoinMessageWithNullGroupId() throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), null, previousMessageId);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsJoinMessageWithNonRawGroupId() throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), "not raw",
previousMessageId);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsJoinMessageWithTooShortPreviousMessageId()
throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(),
getRandomBytes(UniqueId.LENGTH - 1));
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsJoinMessageWithTooLongPreviousMessageId()
throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(),
getRandomBytes(UniqueId.LENGTH + 1));
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsJoinMessageWithNonRawPreviousMessageId()
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(),
"not raw");
validator.validateMessage(message, group, body);
public void testAcceptsJoinMessageWithNullPreviousMessageId()
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), null);
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(),
message.getTimestamp(), false, false, false, false);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
assertEquals(0, messageContext.getDependencies().size());
assertEquals(meta, messageContext.getDictionary());
}
@Test
public void testAcceptsValidJoinMessage() throws Exception {
BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(),
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(),
message.getTimestamp(), false, false, false, false);
will(returnValue(meta));
}});
validator.validateMessage(message, group, body);
assertEquals(1, messageContext.getDependencies().size());
assertEquals(previousMessageId,
messageContext.getDependencies().iterator().next());
assertEquals(meta, messageContext.getDictionary());
}
// LEAVE message
@Test(expected = FormatException.class)
public void testRejectsTooShortLeaveMessage() throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId());
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsTooLongLeaveMessage() throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(),
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsLeaveMessageWithTooShortGroupId() throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(),
getRandomBytes(GroupId.LENGTH - 1), previousMessageId);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsLeaveMessageWithTooLongGroupId() throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(),
getRandomBytes(GroupId.LENGTH + 1), previousMessageId);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsLeaveMessageWithNullGroupId() throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(), null, previousMessageId);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsLeaveMessageWithNonRawGroupId() throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(), "not raw",
previousMessageId);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsLeaveMessageWithTooShortPreviousMessageId()
throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(),
getRandomBytes(UniqueId.LENGTH - 1));
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsLeaveMessageWithTooLongPreviousMessageId()
throws Exception {
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(),
getRandomBytes(UniqueId.LENGTH + 1));
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsLeaveMessageWithNonRawPreviousMessageId()
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(),
"not raw");
validator.validateMessage(message, group, body);
public void testAcceptsLeaveMessageWithNullPreviousMessageId()
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), null);
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(),
message.getTimestamp(), false, false, false, false);
will(returnValue(meta));
}});
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
assertEquals(0, messageContext.getDependencies().size());
assertEquals(meta, messageContext.getDictionary());
}
@Test
public void testAcceptsValidLeaveMessage() throws Exception {
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(),
message.getTimestamp(), false, false, false, false);
will(returnValue(meta));
}});
BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(),
previousMessageId);
BdfMessageContext messageContext =
validator.validateMessage(message, group, body);
assertEquals(1, messageContext.getDependencies().size());
assertEquals(previousMessageId,
messageContext.getDependencies().iterator().next());
assertEquals(meta, messageContext.getDictionary());
}
// ABORT message
@Test(expected = FormatException.class)
public void testRejectsTooShortAbortMessage() throws Exception {
BdfList body = BdfList.of(ABORT.getValue());
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsTooLongAbortMessage() throws Exception {
BdfList body = BdfList.of(ABORT.getValue(), privateGroup.getId(), "");
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsAbortMessageWithTooShortGroupId() throws Exception {
BdfList body = BdfList.of(ABORT.getValue(),
getRandomBytes(GroupId.LENGTH - 1));
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsAbortMessageWithTooLongGroupId() throws Exception {
BdfList body = BdfList.of(ABORT.getValue(),
getRandomBytes(GroupId.LENGTH + 1));
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsAbortMessageWithNullGroupId() throws Exception {
BdfList body = BdfList.of(ABORT.getValue(), null);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsAbortMessageWithNonRawGroupId() throws Exception {
BdfList body = BdfList.of(ABORT.getValue(), "not raw");
validator.validateMessage(message, group, body);
public void testAcceptsValidAbortMessage() throws Exception {
context.checking(new Expectations() {{
oneOf(messageEncoder).encodeMetadata(ABORT, message.getGroupId(),
message.getTimestamp(), false, false, false, false);
will(returnValue(meta));
}});
BdfList body = BdfList.of(ABORT.getValue(), privateGroup.getId());
validator.validateMessage(message, group, body);
assertEquals(0, messageContext.getDependencies().size());
assertEquals(meta, messageContext.getDictionary());
}
@Test(expected = FormatException.class)
public void testRejectsMessageWithUnknownType() throws Exception {
BdfList body = BdfList.of(ABORT.getValue() + 1);
validator.validateMessage(message, group, body);
}
@Test(expected = FormatException.class)
public void testRejectsEmptyMessage() throws Exception {
BdfList body = new BdfList();
validator.validateMessage(message, group, body);