From b37a7531ca8c27a5688be684b21d64dda87a3145 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 23 Nov 2016 18:52:34 -0200 Subject: [PATCH 1/3] Add unit tests for group validators --- .../privategroup/GroupMessageValidator.java | 2 +- .../org/briarproject/ValidatorTestCase.java | 3 + .../GroupMessageValidatorTest.java | 534 ++++++++++++++++++ .../GroupInvitationValidatorTest.java | 424 ++++++++++++++ 4 files changed, 962 insertions(+), 1 deletion(-) create mode 100644 briar-tests/src/org/briarproject/privategroup/GroupMessageValidatorTest.java create mode 100644 briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationValidatorTest.java diff --git a/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java b/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java index 7e27d7468..39b77cd27 100644 --- a/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java +++ b/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java @@ -180,7 +180,7 @@ class GroupMessageValidator extends BdfMessageValidator { // content (string) String content = body.getString(5); - checkLength(content, 0, MAX_GROUP_POST_BODY_LENGTH); + checkLength(content, 1, MAX_GROUP_POST_BODY_LENGTH); // signature (raw) // a signature with the member's private key over a list with 7 elements diff --git a/briar-tests/src/org/briarproject/ValidatorTestCase.java b/briar-tests/src/org/briarproject/ValidatorTestCase.java index 4e5a3b5e6..f7a7693fd 100644 --- a/briar-tests/src/org/briarproject/ValidatorTestCase.java +++ b/briar-tests/src/org/briarproject/ValidatorTestCase.java @@ -2,6 +2,7 @@ package org.briarproject; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.data.MetadataEncoder; +import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.Group; import org.briarproject.api.sync.GroupId; @@ -16,6 +17,8 @@ public abstract class ValidatorTestCase extends BriarMockTestCase { protected final MetadataEncoder metadataEncoder = context.mock(MetadataEncoder.class); protected final Clock clock = context.mock(Clock.class); + protected final AuthorFactory authorFactory = + context.mock(AuthorFactory.class); protected final MessageId messageId = new MessageId(TestUtils.getRandomId()); diff --git a/briar-tests/src/org/briarproject/privategroup/GroupMessageValidatorTest.java b/briar-tests/src/org/briarproject/privategroup/GroupMessageValidatorTest.java new file mode 100644 index 000000000..d9da03860 --- /dev/null +++ b/briar-tests/src/org/briarproject/privategroup/GroupMessageValidatorTest.java @@ -0,0 +1,534 @@ +package org.briarproject.privategroup; + +import org.briarproject.ValidatorTestCase; +import org.briarproject.api.FormatException; +import org.briarproject.api.clients.BdfMessageContext; +import org.briarproject.api.data.BdfDictionary; +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.privategroup.invitation.GroupInvitationFactory; +import org.briarproject.api.sync.InvalidMessageException; +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.GroupMessageFactory.SIGNING_LABEL_JOIN; +import static org.briarproject.api.privategroup.GroupMessageFactory.SIGNING_LABEL_POST; +import static org.briarproject.api.privategroup.MessageType.JOIN; +import static org.briarproject.api.privategroup.MessageType.POST; +import static org.briarproject.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; +import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_POST_BODY_LENGTH; +import static org.briarproject.api.privategroup.invitation.GroupInvitationFactory.SIGNING_LABEL_INVITE; +import static org.briarproject.privategroup.GroupConstants.KEY_INITIAL_JOIN_MSG; +import static org.briarproject.privategroup.GroupConstants.KEY_MEMBER_ID; +import static org.briarproject.privategroup.GroupConstants.KEY_MEMBER_NAME; +import static org.briarproject.privategroup.GroupConstants.KEY_MEMBER_PUBLIC_KEY; +import static org.briarproject.privategroup.GroupConstants.KEY_PARENT_MSG_ID; +import static org.briarproject.privategroup.GroupConstants.KEY_PREVIOUS_MSG_ID; +import static org.briarproject.privategroup.GroupConstants.KEY_READ; +import static org.briarproject.privategroup.GroupConstants.KEY_TIMESTAMP; +import static org.briarproject.privategroup.GroupConstants.KEY_TYPE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class GroupMessageValidatorTest extends ValidatorTestCase { + + private final PrivateGroupFactory privateGroupFactory = + context.mock(PrivateGroupFactory.class); + private final GroupInvitationFactory groupInvitationFactory = + context.mock(GroupInvitationFactory.class); + + + private final String creatorName = "Member Name"; + private final String memberName = "Member Name"; + private final byte[] creatorKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); + private final byte[] memberKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); + private final byte[] creatorSignature = + getRandomBytes(MAX_SIGNATURE_LENGTH); + private final byte[] signature = getRandomBytes(MAX_SIGNATURE_LENGTH); + private final Author member = + new Author(new AuthorId(getRandomId()), memberName, memberKey); + private final Author creator = + new Author(new AuthorId(getRandomId()), creatorName, creatorKey); + private final long inviteTimestamp = 42L; + private final PrivateGroup privateGroup = + new PrivateGroup(group, "Private Group Name", creator, + getRandomBytes(GROUP_SALT_LENGTH)); + private final BdfList token = BdfList.of("token"); + private MessageId parentId = new MessageId(getRandomId()); + private MessageId previousMsgId = new MessageId(getRandomId()); + private String postContent = "Post text"; + + private GroupMessageValidator validator = + new GroupMessageValidator(privateGroupFactory, clientHelper, + metadataEncoder, clock, authorFactory, + groupInvitationFactory); + + @Test(expected = FormatException.class) + public void testRejectTooShortMemberName() throws Exception { + BdfList list = BdfList.of(JOIN.getInt(), "", memberKey, null, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectTooLongMemberName() throws Exception { + BdfList list = BdfList.of(JOIN.getInt(), + getRandomString(MAX_AUTHOR_NAME_LENGTH + 1), memberKey, null, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectTooShortMemberKey() throws Exception { + BdfList list = BdfList.of(JOIN.getInt(), memberName, new byte[0], null, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectTooLongMemberKey() throws Exception { + BdfList list = BdfList.of(JOIN.getInt(), memberName, + getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1), null, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectNonRawMemberKey() throws Exception { + BdfList list = + BdfList.of(JOIN.getInt(), memberName, "non raw key", null, + signature); + validator.validateMessage(message, group, list); + } + + // JOIN message + + @Test(expected = FormatException.class) + public void testRejectsTooShortJoinMessage() throws Exception { + BdfList list = BdfList.of(JOIN.getInt(), creatorName, creatorKey, + null); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsTooLongJoinMessage() throws Exception { + expectCreateAuthor(creator); + BdfList list = BdfList.of(JOIN.getInt(), creatorName, creatorKey, + null, signature, ""); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithNonListInvitation() throws Exception { + expectCreateAuthor(creator); + expectParsePrivateGroup(); + BdfList list = BdfList.of(JOIN.getInt(), creatorName, creatorKey, + "not a list", signature); + validator.validateMessage(message, group, list); + } + + @Test + public void testAcceptCreatorJoinMessage() throws Exception { + final BdfList invite = null; + expectJoinMessage(creator, invite, true, true); + BdfList list = BdfList.of(JOIN.getInt(), creatorName, creatorKey, + invite, signature); + BdfMessageContext messageContext = + validator.validateMessage(message, group, list); + assertMessageContext(messageContext, creator); + assertTrue(messageContext.getDictionary() + .getBoolean(KEY_INITIAL_JOIN_MSG)); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsMemberJoinMessageWithoutInvitation() + throws Exception { + expectCreateAuthor(member); + expectParsePrivateGroup(); + BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, null, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithTooShortInvitation() throws Exception { + BdfList invite = BdfList.of(inviteTimestamp); + expectCreateAuthor(member); + expectParsePrivateGroup(); + BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithTooLongInvitation() throws Exception { + BdfList invite = BdfList.of(inviteTimestamp, creatorSignature, ""); + expectCreateAuthor(member); + expectParsePrivateGroup(); + BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsJoinMessageWithEqualInvitationTime() + throws Exception { + BdfList invite = BdfList.of(message.getTimestamp(), creatorSignature); + expectCreateAuthor(member); + expectParsePrivateGroup(); + BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsJoinMessageWithLaterInvitationTime() + throws Exception { + BdfList invite = + BdfList.of(message.getTimestamp() + 1, creatorSignature); + expectCreateAuthor(member); + expectParsePrivateGroup(); + BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithNonRawCreatorSignature() + throws Exception { + BdfList invite = BdfList.of(inviteTimestamp, "non-raw signature"); + expectCreateAuthor(member); + expectParsePrivateGroup(); + BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithTooShortCreatorSignature() + throws Exception { + BdfList invite = BdfList.of(inviteTimestamp, new byte[0]); + expectCreateAuthor(member); + expectParsePrivateGroup(); + BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithTooLongCreatorSignature() + throws Exception { + BdfList invite = BdfList.of(inviteTimestamp, + getRandomBytes(MAX_SIGNATURE_LENGTH + 1)); + expectCreateAuthor(member); + expectParsePrivateGroup(); + BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsJoinMessageWithInvalidCreatorSignature() + throws Exception { + BdfList invite = BdfList.of(inviteTimestamp, creatorSignature); + expectJoinMessage(member, invite, false, true); + BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsJoinMessageWithInvalidMemberSignature() + throws Exception { + BdfList invite = BdfList.of(inviteTimestamp, creatorSignature); + expectJoinMessage(member, invite, true, false); + BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + validator.validateMessage(message, group, list); + } + + @Test + public void testAcceptMemberJoinMessage() throws Exception { + BdfList invite = BdfList.of(inviteTimestamp, creatorSignature); + expectJoinMessage(member, invite, true, true); + BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + BdfMessageContext messageContext = + validator.validateMessage(message, group, list); + assertMessageContext(messageContext, member); + assertFalse(messageContext.getDictionary() + .getBoolean(KEY_INITIAL_JOIN_MSG)); + } + + private void expectCreateAuthor(final Author member) { + context.checking(new Expectations() {{ + oneOf(authorFactory) + .createAuthor(member.getName(), member.getPublicKey()); + will(returnValue(member)); + }}); + } + + private void expectParsePrivateGroup() throws Exception { + context.checking(new Expectations() {{ + oneOf(privateGroupFactory).parsePrivateGroup(group); + will(returnValue(privateGroup)); + }}); + } + + private void expectJoinMessage(final Author member, final BdfList invite, + final boolean creatorSigValid, final boolean memberSigValid) + throws Exception { + final BdfList signed = + BdfList.of(group.getId(), message.getTimestamp(), JOIN.getInt(), + member.getName(), member.getPublicKey(), invite); + expectCreateAuthor(member); + expectParsePrivateGroup(); + context.checking(new Expectations() {{ + if (invite != null) { + oneOf(groupInvitationFactory) + .createInviteToken(creator.getId(), member.getId(), + privateGroup.getId(), inviteTimestamp); + will(returnValue(token)); + oneOf(clientHelper) + .verifySignature(SIGNING_LABEL_INVITE, creatorSignature, + creatorKey, token); + if (!memberSigValid) + will(throwException(new GeneralSecurityException())); + } + if (memberSigValid) { + oneOf(clientHelper) + .verifySignature(SIGNING_LABEL_JOIN, signature, + member.getPublicKey(), signed); + if (!creatorSigValid) + will(throwException(new GeneralSecurityException())); + } + }}); + } + + // POST Message + + @Test(expected = FormatException.class) + public void testRejectsTooShortPost() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + previousMsgId, postContent); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsTooLongPost() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + previousMsgId, postContent, signature, ""); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithNonRawParentId() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, "non-raw", + previousMsgId, postContent, signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithTooShortParentId() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, + getRandomBytes(MessageId.LENGTH - 1), previousMsgId, + postContent, signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithTooLongParentId() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, + getRandomBytes(MessageId.LENGTH + 1), previousMsgId, + postContent, signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithNonRawPreviousMsgId() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + "non-raw", postContent, signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithTooShortPreviousMsgId() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + getRandomBytes(MessageId.LENGTH - 1), + postContent, signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithTooLongPreviousMsgId() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + getRandomBytes(MessageId.LENGTH + 1), + postContent, signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithEmptyContent() throws Exception { + postContent = ""; + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + previousMsgId, postContent, signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithTooLongContent() throws Exception { + postContent = getRandomString(MAX_GROUP_POST_BODY_LENGTH + 1); + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + previousMsgId, postContent, signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithNonStringContent() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + previousMsgId, getRandomBytes(5), signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithEmptySignature() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + previousMsgId, postContent, new byte[0]); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithTooLongSignature() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + previousMsgId, postContent, + getRandomBytes(MAX_SIGNATURE_LENGTH + 1)); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithNonRawSignature() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + previousMsgId, postContent, "non-raw"); + expectCreateAuthor(member); + validator.validateMessage(message, group, list); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsPostWithInvalidSignature() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + previousMsgId, postContent, signature); + expectPostMessage(member, false); + validator.validateMessage(message, group, list); + } + + @Test + public void testAcceptPost() throws Exception { + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + previousMsgId, postContent, signature); + expectPostMessage(member, true); + BdfMessageContext messageContext = + validator.validateMessage(message, group, list); + assertMessageContext(messageContext, member); + assertEquals(previousMsgId.getBytes(), + messageContext.getDictionary().getRaw(KEY_PREVIOUS_MSG_ID)); + assertEquals(parentId.getBytes(), + messageContext.getDictionary().getRaw(KEY_PARENT_MSG_ID)); + } + + @Test + public void testAcceptTopLevelPost() throws Exception { + parentId = null; + BdfList list = + BdfList.of(POST.getInt(), memberName, memberKey, parentId, + previousMsgId, postContent, signature); + expectPostMessage(member, true); + BdfMessageContext messageContext = + validator.validateMessage(message, group, list); + assertMessageContext(messageContext, member); + assertEquals(previousMsgId.getBytes(), + messageContext.getDictionary().getRaw(KEY_PREVIOUS_MSG_ID)); + assertFalse( + messageContext.getDictionary().containsKey(KEY_PARENT_MSG_ID)); + } + + private void expectPostMessage(final Author member, final boolean sigValid) + throws Exception { + final BdfList signed = + BdfList.of(group.getId(), message.getTimestamp(), POST.getInt(), + member.getName(), member.getPublicKey(), + parentId == null ? null : parentId.getBytes(), + previousMsgId == null ? null : previousMsgId.getBytes(), + postContent); + expectCreateAuthor(member); + context.checking(new Expectations() {{ + oneOf(clientHelper) + .verifySignature(SIGNING_LABEL_POST, signature, + member.getPublicKey(), signed); + if (!sigValid) will(throwException(new GeneralSecurityException())); + }}); + } + + private void assertMessageContext(BdfMessageContext c, Author member) + throws FormatException { + BdfDictionary d = c.getDictionary(); + assertTrue(message.getTimestamp() == d.getLong(KEY_TIMESTAMP)); + assertFalse(d.getBoolean(KEY_READ)); + assertEquals(member.getId().getBytes(), d.getRaw(KEY_MEMBER_ID)); + assertEquals(member.getName(), d.getString(KEY_MEMBER_NAME)); + assertEquals(member.getPublicKey(), d.getRaw(KEY_MEMBER_PUBLIC_KEY)); + + // assert message dependencies + if (d.getLong(KEY_TYPE) == POST.getInt()) { + assertTrue(c.getDependencies().contains(previousMsgId)); + if (parentId != null) { + assertTrue(c.getDependencies().contains(parentId)); + } else { + assertFalse(c.getDependencies().contains(parentId)); + } + } else { + assertEquals(JOIN.getInt(), d.getLong(KEY_TYPE).intValue()); + } + } + +} diff --git a/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationValidatorTest.java b/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationValidatorTest.java new file mode 100644 index 000000000..093de60f3 --- /dev/null +++ b/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationValidatorTest.java @@ -0,0 +1,424 @@ +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 = "Group Name"; + private final String creatorName = "Creator Name"; + 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 = "Invitation Text"; + 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 GroupInvitationValidator validator = + new GroupInvitationValidator(clientHelper, metadataEncoder, + clock, authorFactory, privateGroupFactory, messageEncoder); + + @Test(expected = FormatException.class) + public void testRejectsTooShortInviteMessage() throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + creatorKey, salt, inviteText); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsTooLongInviteMessage() throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + creatorKey, salt, inviteText, signature, ""); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithTooLongGroupName() + throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), + getRandomString(MAX_GROUP_NAME_LENGTH + 1), creatorName, + creatorKey, salt, inviteText, signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithEmptyGroupName() + throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), "", creatorName, + creatorKey, salt, inviteText, signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithTooLongCreatorName() + throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), groupName, + getRandomString(MAX_AUTHOR_NAME_LENGTH + 1), creatorKey, salt, + inviteText, signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithEmptyCreatorName() + throws Exception { + BdfList list = + BdfList.of(INVITE.getValue(), groupName, "", creatorKey, salt, + inviteText, signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithTooLongCreatorKey() + throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1), salt, inviteText, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithEmptyCreatorKey() + throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + new byte[0], salt, inviteText, signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithTooLongGroupSalt() + throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + creatorKey, getRandomBytes(GROUP_SALT_LENGTH + 1), inviteText, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithTooShortGroupSalt() + throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + creatorKey, getRandomBytes(GROUP_SALT_LENGTH - 1), inviteText, + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithTooLongMessage() + throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + creatorKey, salt, + getRandomString(MAX_GROUP_INVITATION_MSG_LENGTH + 1), + signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithTooLongSignature() + throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + creatorKey, salt, inviteText, + getRandomBytes(MAX_SIGNATURE_LENGTH + 1)); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithEmptySignature() + throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + creatorKey, salt, inviteText, new byte[0]); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithNullSignature() + throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + creatorKey, salt, inviteText, null); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithNonRawSignature() + throws Exception { + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + creatorKey, salt, inviteText, "non raw signature"); + validator.validateMessage(message, group, list); + } + + @Test + public void testAcceptsInviteMessageWithNullMessage() + throws Exception { + expectInviteMessage(false); + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + creatorKey, salt, null, signature); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsInviteMessageWithInvalidSignature() + throws Exception { + expectInviteMessage(true); + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + creatorKey, salt, null, signature); + validator.validateMessage(message, group, list); + } + + @Test + public void testAcceptsProperInviteMessage() + throws Exception { + expectInviteMessage(false); + BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + creatorKey, salt, inviteText, signature); + BdfMessageContext messageContext = + validator.validateMessage(message, group, list); + assertTrue(messageContext.getDependencies().isEmpty()); + assertEquals(meta ,messageContext.getDictionary()); + } + + private void expectInviteMessage(final boolean exception) throws Exception { + final BdfList toSign = + 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, toSign); + 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 list = BdfList.of(JOIN.getValue(), privateGroup.getId()); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsTooLongJoinMessage() throws Exception { + BdfList list = BdfList.of(JOIN.getValue(), privateGroup.getId(), + previousMessageId, ""); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithTooLongGroupId() throws Exception { + BdfList list = + BdfList.of(JOIN.getValue(), getRandomBytes(GroupId.LENGTH + 1), + previousMessageId); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithTooShortGroupId() throws Exception { + BdfList list = + BdfList.of(JOIN.getValue(), getRandomBytes(GroupId.LENGTH - 1), + previousMessageId); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithTooLongPreviousMessageId() + throws Exception { + BdfList list = BdfList.of(JOIN.getValue(), privateGroup.getId(), + getRandomBytes(UniqueId.LENGTH + 1)); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithTooShortPreviousMessageId() + throws Exception { + BdfList list = BdfList.of(JOIN.getValue(), privateGroup.getId(), + getRandomBytes(UniqueId.LENGTH - 1)); + validator.validateMessage(message, group, list); + } + + @Test + public void testAcceptsProperJoinMessage() + throws Exception { + context.checking(new Expectations() {{ + oneOf(messageEncoder) + .encodeMetadata(JOIN, message.getGroupId(), + message.getTimestamp(), false, false, false, + false); + will(returnValue(meta)); + }}); + BdfList list = BdfList.of(JOIN.getValue(), privateGroup.getId(), + previousMessageId); + BdfMessageContext messageContext = + validator.validateMessage(message, group, list); + 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 list = BdfList.of(LEAVE.getValue(), privateGroup.getId()); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsTooLongLeaveMessage() throws Exception { + BdfList list = BdfList.of(LEAVE.getValue(), privateGroup.getId(), + previousMessageId, ""); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsLeaveMessageWithTooLongGroupId() throws Exception { + BdfList list = + BdfList.of(LEAVE.getValue(), getRandomBytes(GroupId.LENGTH + 1), + previousMessageId); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsLeaveMessageWithTooShortGroupId() throws Exception { + BdfList list = + BdfList.of(LEAVE.getValue(), getRandomBytes(GroupId.LENGTH - 1), + previousMessageId); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsLeaveMessageWithTooLongPreviousMessageId() + throws Exception { + BdfList list = BdfList.of(LEAVE.getValue(), privateGroup.getId(), + getRandomBytes(UniqueId.LENGTH + 1)); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsLeaveMessageWithTooShortPreviousMessageId() + throws Exception { + BdfList list = BdfList.of(LEAVE.getValue(), privateGroup.getId(), + getRandomBytes(UniqueId.LENGTH - 1)); + validator.validateMessage(message, group, list); + } + + @Test + public void testAcceptsProperLeaveMessage() + throws Exception { + context.checking(new Expectations() {{ + oneOf(messageEncoder).encodeMetadata(LEAVE, message.getGroupId(), + message.getTimestamp(), false, false, false, false); + will(returnValue(meta)); + }}); + BdfList list = BdfList.of(LEAVE.getValue(), privateGroup.getId(), + previousMessageId); + BdfMessageContext messageContext = + validator.validateMessage(message, group, list); + 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 list = BdfList.of(ABORT.getValue()); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsTooLongAbortMessage() throws Exception { + BdfList list = BdfList.of(ABORT.getValue(), privateGroup.getId(), ""); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsAbortMessageWithTooLongGroupId() throws Exception { + BdfList list = BdfList.of(ABORT.getValue(), + getRandomBytes(GroupId.LENGTH + 1)); + validator.validateMessage(message, group, list); + } + + @Test(expected = FormatException.class) + public void testRejectsAbortMessageWithTooShortGroupId() throws Exception { + BdfList list = BdfList.of(ABORT.getValue(), + getRandomBytes(GroupId.LENGTH - 1)); + validator.validateMessage(message, group, list); + } + + @Test + public void testAcceptsProperAbortMessage() + throws Exception { + context.checking(new Expectations() {{ + oneOf(messageEncoder).encodeMetadata(ABORT, message.getGroupId(), + message.getTimestamp(), false, false, false, false); + will(returnValue(meta)); + }}); + BdfList list = BdfList.of(ABORT.getValue(), privateGroup.getId()); + BdfMessageContext messageContext = + validator.validateMessage(message, group, list); + assertEquals(0, messageContext.getDependencies().size()); + assertEquals(meta ,messageContext.getDictionary()); + } + + @Test(expected = FormatException.class) + public void testRejectsMessageWithUnknownType() throws Exception { + BdfList list = BdfList.of(ABORT.getValue() + 1); + validator.validateMessage(message, group, list); + } + +} From 050111a99428df99170514243d146336d30eca3a Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 29 Nov 2016 17:46:46 +0000 Subject: [PATCH 2/3] Added some more private group validation tests, found a bug. --- .../privategroup/GroupMessageValidator.java | 25 +- .../GroupMessageValidatorTest.java | 580 +++++++++++------- 2 files changed, 358 insertions(+), 247 deletions(-) diff --git a/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java b/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java index 39b77cd27..76f5b6b37 100644 --- a/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java +++ b/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java @@ -9,7 +9,6 @@ import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.identity.Author; import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.nullsafety.NotNullByDefault; -import org.briarproject.api.privategroup.MessageType; import org.briarproject.api.privategroup.PrivateGroup; import org.briarproject.api.privategroup.PrivateGroupFactory; import org.briarproject.api.privategroup.invitation.GroupInvitationFactory; @@ -79,17 +78,14 @@ class GroupMessageValidator extends BdfMessageValidator { Author member = authorFactory.createAuthor(memberName, memberPublicKey); BdfMessageContext c; - switch (MessageType.valueOf(type)) { - case JOIN: - c = validateJoin(m, g, body, member); - addMessageMetadata(c, member, m.getTimestamp()); - break; - case POST: - c = validatePost(m, g, body, member); - addMessageMetadata(c, member, m.getTimestamp()); - break; - default: - throw new InvalidMessageException("Unknown Message Type"); + if (type == JOIN.getInt()) { + c = validateJoin(m, g, body, member); + addMessageMetadata(c, member, m.getTimestamp()); + } else if (type == POST.getInt()) { + c = validatePost(m, g, body, member); + addMessageMetadata(c, member, m.getTimestamp()); + } else { + throw new InvalidMessageException("Unknown Message Type"); } c.getDictionary().put(KEY_TYPE, type); return c; @@ -133,8 +129,9 @@ class GroupMessageValidator extends BdfMessageValidator { .createInviteToken(creator.getId(), member.getId(), pg.getId(), inviteTimestamp); try { - clientHelper.verifySignature(SIGNING_LABEL_INVITE, creatorSignature, - creator.getPublicKey(), token); + clientHelper + .verifySignature(SIGNING_LABEL_INVITE, creatorSignature, + creator.getPublicKey(), token); } catch (GeneralSecurityException e) { throw new InvalidMessageException(e); } diff --git a/briar-tests/src/org/briarproject/privategroup/GroupMessageValidatorTest.java b/briar-tests/src/org/briarproject/privategroup/GroupMessageValidatorTest.java index d9da03860..cff74d31d 100644 --- a/briar-tests/src/org/briarproject/privategroup/GroupMessageValidatorTest.java +++ b/briar-tests/src/org/briarproject/privategroup/GroupMessageValidatorTest.java @@ -7,6 +7,7 @@ import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfList; import org.briarproject.api.identity.Author; import org.briarproject.api.identity.AuthorId; +import org.briarproject.api.privategroup.MessageType; import org.briarproject.api.privategroup.PrivateGroup; import org.briarproject.api.privategroup.PrivateGroupFactory; import org.briarproject.api.privategroup.invitation.GroupInvitationFactory; @@ -16,6 +17,9 @@ import org.jmock.Expectations; import org.junit.Test; import java.security.GeneralSecurityException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import static org.briarproject.TestUtils.getRandomBytes; import static org.briarproject.TestUtils.getRandomId; @@ -28,6 +32,7 @@ import static org.briarproject.api.privategroup.GroupMessageFactory.SIGNING_LABE import static org.briarproject.api.privategroup.MessageType.JOIN; import static org.briarproject.api.privategroup.MessageType.POST; import static org.briarproject.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; +import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_POST_BODY_LENGTH; import static org.briarproject.api.privategroup.invitation.GroupInvitationFactory.SIGNING_LABEL_INVITE; import static org.briarproject.privategroup.GroupConstants.KEY_INITIAL_JOIN_MSG; @@ -39,6 +44,7 @@ import static org.briarproject.privategroup.GroupConstants.KEY_PREVIOUS_MSG_ID; import static org.briarproject.privategroup.GroupConstants.KEY_READ; import static org.briarproject.privategroup.GroupConstants.KEY_TIMESTAMP; import static org.briarproject.privategroup.GroupConstants.KEY_TYPE; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -50,9 +56,8 @@ public class GroupMessageValidatorTest extends ValidatorTestCase { private final GroupInvitationFactory groupInvitationFactory = context.mock(GroupInvitationFactory.class); - - private final String creatorName = "Member Name"; - private final String memberName = "Member Name"; + private final String creatorName = getRandomString(MAX_AUTHOR_NAME_LENGTH); + private final String memberName = getRandomString(MAX_AUTHOR_NAME_LENGTH); private final byte[] creatorKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); private final byte[] memberKey = getRandomBytes(MAX_PUBLIC_KEY_LENGTH); private final byte[] creatorSignature = @@ -63,220 +68,272 @@ public class GroupMessageValidatorTest extends ValidatorTestCase { private final Author creator = new Author(new AuthorId(getRandomId()), creatorName, creatorKey); private final long inviteTimestamp = 42L; - private final PrivateGroup privateGroup = - new PrivateGroup(group, "Private Group Name", creator, - getRandomBytes(GROUP_SALT_LENGTH)); + private final PrivateGroup privateGroup = new PrivateGroup(group, + getRandomString(MAX_GROUP_NAME_LENGTH), creator, + getRandomBytes(GROUP_SALT_LENGTH)); private final BdfList token = BdfList.of("token"); - private MessageId parentId = new MessageId(getRandomId()); - private MessageId previousMsgId = new MessageId(getRandomId()); - private String postContent = "Post text"; + private final MessageId parentId = new MessageId(getRandomId()); + private final MessageId previousMsgId = new MessageId(getRandomId()); + private final String postContent = + getRandomString(MAX_GROUP_POST_BODY_LENGTH); - private GroupMessageValidator validator = + private final GroupMessageValidator validator = new GroupMessageValidator(privateGroupFactory, clientHelper, metadataEncoder, clock, authorFactory, groupInvitationFactory); - @Test(expected = FormatException.class) - public void testRejectTooShortMemberName() throws Exception { - BdfList list = BdfList.of(JOIN.getInt(), "", memberKey, null, - signature); - validator.validateMessage(message, group, list); - } - - @Test(expected = FormatException.class) - public void testRejectTooLongMemberName() throws Exception { - BdfList list = BdfList.of(JOIN.getInt(), - getRandomString(MAX_AUTHOR_NAME_LENGTH + 1), memberKey, null, - signature); - validator.validateMessage(message, group, list); - } - - @Test(expected = FormatException.class) - public void testRejectTooShortMemberKey() throws Exception { - BdfList list = BdfList.of(JOIN.getInt(), memberName, new byte[0], null, - signature); - validator.validateMessage(message, group, list); - } - - @Test(expected = FormatException.class) - public void testRejectTooLongMemberKey() throws Exception { - BdfList list = BdfList.of(JOIN.getInt(), memberName, - getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1), null, - signature); - validator.validateMessage(message, group, list); - } - - @Test(expected = FormatException.class) - public void testRejectNonRawMemberKey() throws Exception { - BdfList list = - BdfList.of(JOIN.getInt(), memberName, "non raw key", null, - signature); - validator.validateMessage(message, group, list); - } - // JOIN message @Test(expected = FormatException.class) public void testRejectsTooShortJoinMessage() throws Exception { - BdfList list = BdfList.of(JOIN.getInt(), creatorName, creatorKey, - null); - validator.validateMessage(message, group, list); + BdfList body = BdfList.of(JOIN.getInt(), creatorName, creatorKey, null); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsTooLongJoinMessage() throws Exception { expectCreateAuthor(creator); - BdfList list = BdfList.of(JOIN.getInt(), creatorName, creatorKey, - null, signature, ""); - validator.validateMessage(message, group, list); + BdfList body = BdfList.of(JOIN.getInt(), creatorName, creatorKey, null, + signature, ""); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsJoinMessageWithNonListInvitation() throws Exception { + public void testRejectsJoinWithTooShortMemberName() throws Exception { + BdfList body = BdfList.of(JOIN.getInt(), "", memberKey, null, + signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithTooLongMemberName() throws Exception { + BdfList body = BdfList.of(JOIN.getInt(), + getRandomString(MAX_AUTHOR_NAME_LENGTH + 1), memberKey, null, + signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithNullMemberName() throws Exception { + BdfList body = BdfList.of(JOIN.getInt(), null, memberKey, null, + signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinMessageWithNonStringMemberName() throws Exception { + BdfList body = BdfList.of(JOIN.getInt(), getRandomBytes(5), memberKey, + null, signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinWithTooShortMemberKey() throws Exception { + BdfList body = BdfList.of(JOIN.getInt(), memberName, new byte[0], null, + signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinWithTooLongMemberKey() throws Exception { + BdfList body = BdfList.of(JOIN.getInt(), memberName, + getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1), null, signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinWithNoullMemberKey() throws Exception { + BdfList body = BdfList.of(JOIN.getInt(), memberName, null, null, + signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinWithNonRawMemberKey() throws Exception { + BdfList body = BdfList.of(JOIN.getInt(), memberName, "not raw", null, + signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsJoinWithNonListInvitation() throws Exception { expectCreateAuthor(creator); expectParsePrivateGroup(); - BdfList list = BdfList.of(JOIN.getInt(), creatorName, creatorKey, + BdfList body = BdfList.of(JOIN.getInt(), creatorName, creatorKey, "not a list", signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test - public void testAcceptCreatorJoinMessage() throws Exception { - final BdfList invite = null; - expectJoinMessage(creator, invite, true, true); - BdfList list = BdfList.of(JOIN.getInt(), creatorName, creatorKey, - invite, signature); + public void testAcceptsCreatorJoin() throws Exception { + expectJoinMessage(creator, null, true, true); + BdfList body = BdfList.of(JOIN.getInt(), creatorName, creatorKey, + null, signature); BdfMessageContext messageContext = - validator.validateMessage(message, group, list); - assertMessageContext(messageContext, creator); + validator.validateMessage(message, group, body); + assertExpectedMessageContext(messageContext, JOIN, creator, + Collections.emptyList()); assertTrue(messageContext.getDictionary() .getBoolean(KEY_INITIAL_JOIN_MSG)); } @Test(expected = InvalidMessageException.class) - public void testRejectsMemberJoinMessageWithoutInvitation() - throws Exception { + public void testRejectsMemberJoinWithNullInvitation() throws Exception { expectCreateAuthor(member); expectParsePrivateGroup(); - BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, null, + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, null, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsJoinMessageWithTooShortInvitation() throws Exception { + public void testRejectsMemberJoinWithTooShortInvitation() throws Exception { BdfList invite = BdfList.of(inviteTimestamp); expectCreateAuthor(member); expectParsePrivateGroup(); - BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsJoinMessageWithTooLongInvitation() throws Exception { + public void testRejectsMemberJoinWithTooLongInvitation() throws Exception { BdfList invite = BdfList.of(inviteTimestamp, creatorSignature, ""); expectCreateAuthor(member); expectParsePrivateGroup(); - BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = InvalidMessageException.class) - public void testRejectsJoinMessageWithEqualInvitationTime() + public void testRejectsMemberJoinWithEqualInvitationTime() throws Exception { BdfList invite = BdfList.of(message.getTimestamp(), creatorSignature); expectCreateAuthor(member); expectParsePrivateGroup(); - BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = InvalidMessageException.class) - public void testRejectsJoinMessageWithLaterInvitationTime() + public void testRejectsMemberJoinWithLaterInvitationTime() throws Exception { - BdfList invite = - BdfList.of(message.getTimestamp() + 1, creatorSignature); + BdfList invite = BdfList.of(message.getTimestamp() + 1, + creatorSignature); expectCreateAuthor(member); expectParsePrivateGroup(); - BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsJoinMessageWithNonRawCreatorSignature() + public void testRejectsMemberJoinWithNullInvitationTime() throws Exception { - BdfList invite = BdfList.of(inviteTimestamp, "non-raw signature"); + BdfList invite = BdfList.of(null, creatorSignature); expectCreateAuthor(member); expectParsePrivateGroup(); - BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsJoinMessageWithTooShortCreatorSignature() + public void testRejectsMemberJoinWithNonLongInvitationTime() + throws Exception { + BdfList invite = BdfList.of("not long", creatorSignature); + expectCreateAuthor(member); + expectParsePrivateGroup(); + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsMemberJoinWithTooShortCreatorSignature() throws Exception { BdfList invite = BdfList.of(inviteTimestamp, new byte[0]); expectCreateAuthor(member); expectParsePrivateGroup(); - BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsJoinMessageWithTooLongCreatorSignature() + public void testRejectsJoinWithTooLongCreatorSignature() throws Exception { BdfList invite = BdfList.of(inviteTimestamp, getRandomBytes(MAX_SIGNATURE_LENGTH + 1)); expectCreateAuthor(member); expectParsePrivateGroup(); - BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsMemberJoinWithNullCreatorSignature() + throws Exception { + BdfList invite = BdfList.of(inviteTimestamp, null); + expectCreateAuthor(member); + expectParsePrivateGroup(); + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsMemberJoinWithNonRawCreatorSignature() + throws Exception { + BdfList invite = BdfList.of(inviteTimestamp, "not raw"); + expectCreateAuthor(member); + expectParsePrivateGroup(); + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + signature); + validator.validateMessage(message, group, body); } @Test(expected = InvalidMessageException.class) - public void testRejectsJoinMessageWithInvalidCreatorSignature() + public void testRejectsMemberJoinWithInvalidCreatorSignature() throws Exception { BdfList invite = BdfList.of(inviteTimestamp, creatorSignature); expectJoinMessage(member, invite, false, true); - BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = InvalidMessageException.class) - public void testRejectsJoinMessageWithInvalidMemberSignature() + public void testRejectsMemberJoinWithInvalidMemberSignature() throws Exception { BdfList invite = BdfList.of(inviteTimestamp, creatorSignature); expectJoinMessage(member, invite, true, false); - BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test - public void testAcceptMemberJoinMessage() throws Exception { + public void testAcceptsMemberJoin() throws Exception { BdfList invite = BdfList.of(inviteTimestamp, creatorSignature); expectJoinMessage(member, invite, true, true); - BdfList list = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, + BdfList body = BdfList.of(JOIN.getInt(), memberName, memberKey, invite, signature); BdfMessageContext messageContext = - validator.validateMessage(message, group, list); - assertMessageContext(messageContext, member); + validator.validateMessage(message, group, body); + assertExpectedMessageContext(messageContext, JOIN, member, + Collections.emptyList()); assertFalse(messageContext.getDictionary() .getBoolean(KEY_INITIAL_JOIN_MSG)); } private void expectCreateAuthor(final Author member) { context.checking(new Expectations() {{ - oneOf(authorFactory) - .createAuthor(member.getName(), member.getPublicKey()); + oneOf(authorFactory).createAuthor(member.getName(), + member.getPublicKey()); will(returnValue(member)); }}); } @@ -291,27 +348,23 @@ public class GroupMessageValidatorTest extends ValidatorTestCase { private void expectJoinMessage(final Author member, final BdfList invite, final boolean creatorSigValid, final boolean memberSigValid) throws Exception { - final BdfList signed = - BdfList.of(group.getId(), message.getTimestamp(), JOIN.getInt(), - member.getName(), member.getPublicKey(), invite); + final BdfList signed = BdfList.of(group.getId(), message.getTimestamp(), + JOIN.getInt(), member.getName(), member.getPublicKey(), invite); expectCreateAuthor(member); expectParsePrivateGroup(); context.checking(new Expectations() {{ if (invite != null) { - oneOf(groupInvitationFactory) - .createInviteToken(creator.getId(), member.getId(), - privateGroup.getId(), inviteTimestamp); + oneOf(groupInvitationFactory).createInviteToken(creator.getId(), + member.getId(), privateGroup.getId(), inviteTimestamp); will(returnValue(token)); - oneOf(clientHelper) - .verifySignature(SIGNING_LABEL_INVITE, creatorSignature, - creatorKey, token); + oneOf(clientHelper).verifySignature(SIGNING_LABEL_INVITE, + creatorSignature, creatorKey, token); if (!memberSigValid) will(throwException(new GeneralSecurityException())); } if (memberSigValid) { - oneOf(clientHelper) - .verifySignature(SIGNING_LABEL_JOIN, signature, - member.getPublicKey(), signed); + oneOf(clientHelper).verifySignature(SIGNING_LABEL_JOIN, + signature, member.getPublicKey(), signed); if (!creatorSigValid) will(throwException(new GeneralSecurityException())); } @@ -322,213 +375,274 @@ public class GroupMessageValidatorTest extends ValidatorTestCase { @Test(expected = FormatException.class) public void testRejectsTooShortPost() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - previousMsgId, postContent); + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, previousMsgId, postContent); expectCreateAuthor(member); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsTooLongPost() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - previousMsgId, postContent, signature, ""); - validator.validateMessage(message, group, list); + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, previousMsgId, postContent, signature, ""); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsPostWithNonRawParentId() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, "non-raw", - previousMsgId, postContent, signature); - expectCreateAuthor(member); - validator.validateMessage(message, group, list); + public void testRejectsPostWithTooShortMemberName() throws Exception { + BdfList body = BdfList.of(POST.getInt(), "", memberKey, parentId, + previousMsgId, postContent, signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithTooLongMemberName() throws Exception { + BdfList body = BdfList.of(POST.getInt(), + getRandomString(MAX_AUTHOR_NAME_LENGTH + 1), memberKey, + parentId, previousMsgId, postContent, signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithNullMemberName() throws Exception { + BdfList body = BdfList.of(POST.getInt(), null, memberKey, + parentId, previousMsgId, postContent, signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithNonStringMemberName() throws Exception { + BdfList body = BdfList.of(POST.getInt(), getRandomBytes(5), memberKey, + parentId, previousMsgId, postContent, signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithTooShortMemberKey() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, new byte[0], + parentId, previousMsgId, postContent, signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithTooLongMemberKey() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, + getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1), parentId, + previousMsgId, postContent, signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithNullMemberKey() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, null, + parentId, previousMsgId, postContent, signature); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithNonRawMemberKey() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, "not raw", + parentId, previousMsgId, postContent, signature); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsPostWithTooShortParentId() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, - getRandomBytes(MessageId.LENGTH - 1), previousMsgId, - postContent, signature); + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + getRandomBytes(MessageId.LENGTH - 1), previousMsgId, + postContent, signature); expectCreateAuthor(member); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsPostWithTooLongParentId() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, - getRandomBytes(MessageId.LENGTH + 1), previousMsgId, - postContent, signature); + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + getRandomBytes(MessageId.LENGTH + 1), previousMsgId, + postContent, signature); expectCreateAuthor(member); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsPostWithNonRawPreviousMsgId() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - "non-raw", postContent, signature); + public void testRejectsPostWithNonRawParentId() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + "not raw", previousMsgId, postContent, signature); expectCreateAuthor(member); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsPostWithTooShortPreviousMsgId() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - getRandomBytes(MessageId.LENGTH - 1), - postContent, signature); + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, getRandomBytes(MessageId.LENGTH - 1), postContent, + signature); expectCreateAuthor(member); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsPostWithTooLongPreviousMsgId() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - getRandomBytes(MessageId.LENGTH + 1), - postContent, signature); + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, getRandomBytes(MessageId.LENGTH + 1), postContent, + signature); expectCreateAuthor(member); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsPostWithEmptyContent() throws Exception { - postContent = ""; - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - previousMsgId, postContent, signature); + public void testRejectsPostWithNullPreviousMsgId() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, null, postContent, signature); expectCreateAuthor(member); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithNonRawPreviousMsgId() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, "not raw", postContent, signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithTooShortContent() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, previousMsgId, "", signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsPostWithTooLongContent() throws Exception { - postContent = getRandomString(MAX_GROUP_POST_BODY_LENGTH + 1); - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - previousMsgId, postContent, signature); + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, previousMsgId, + getRandomString(MAX_GROUP_POST_BODY_LENGTH + 1), signature); expectCreateAuthor(member); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithNullContent() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, previousMsgId, null, signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsPostWithNonStringContent() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - previousMsgId, getRandomBytes(5), signature); + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, previousMsgId, getRandomBytes(5), signature); expectCreateAuthor(member); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsPostWithEmptySignature() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - previousMsgId, postContent, new byte[0]); + public void testRejectsPostWithTooShortSignature() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, previousMsgId, postContent, new byte[0]); expectCreateAuthor(member); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsPostWithTooLongSignature() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - previousMsgId, postContent, - getRandomBytes(MAX_SIGNATURE_LENGTH + 1)); + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, previousMsgId, postContent, + getRandomBytes(MAX_SIGNATURE_LENGTH + 1)); expectCreateAuthor(member); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); + } + + @Test(expected = FormatException.class) + public void testRejectsPostWithNullSignature() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, previousMsgId, postContent,null); + expectCreateAuthor(member); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsPostWithNonRawSignature() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - previousMsgId, postContent, "non-raw"); + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, previousMsgId, postContent, "not raw"); expectCreateAuthor(member); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = InvalidMessageException.class) public void testRejectsPostWithInvalidSignature() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - previousMsgId, postContent, signature); - expectPostMessage(member, false); - validator.validateMessage(message, group, list); + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, previousMsgId, postContent, signature); + expectPostMessage(member, parentId, false); + validator.validateMessage(message, group, body); } @Test - public void testAcceptPost() throws Exception { - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - previousMsgId, postContent, signature); - expectPostMessage(member, true); + public void testAcceptsPost() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, + parentId, previousMsgId, postContent, signature); + expectPostMessage(member, parentId, true); BdfMessageContext messageContext = - validator.validateMessage(message, group, list); - assertMessageContext(messageContext, member); - assertEquals(previousMsgId.getBytes(), + validator.validateMessage(message, group, body); + assertExpectedMessageContext(messageContext, POST, member, + Arrays.asList(parentId, previousMsgId)); + assertArrayEquals(previousMsgId.getBytes(), messageContext.getDictionary().getRaw(KEY_PREVIOUS_MSG_ID)); - assertEquals(parentId.getBytes(), + assertArrayEquals(parentId.getBytes(), messageContext.getDictionary().getRaw(KEY_PARENT_MSG_ID)); } @Test - public void testAcceptTopLevelPost() throws Exception { - parentId = null; - BdfList list = - BdfList.of(POST.getInt(), memberName, memberKey, parentId, - previousMsgId, postContent, signature); - expectPostMessage(member, true); + public void testAcceptsTopLevelPost() throws Exception { + BdfList body = BdfList.of(POST.getInt(), memberName, memberKey, null, + previousMsgId, postContent, signature); + expectPostMessage(member, null, true); BdfMessageContext messageContext = - validator.validateMessage(message, group, list); - assertMessageContext(messageContext, member); - assertEquals(previousMsgId.getBytes(), + validator.validateMessage(message, group, body); + assertExpectedMessageContext(messageContext, POST, member, + Collections.singletonList(previousMsgId)); + assertArrayEquals(previousMsgId.getBytes(), messageContext.getDictionary().getRaw(KEY_PREVIOUS_MSG_ID)); assertFalse( messageContext.getDictionary().containsKey(KEY_PARENT_MSG_ID)); } - private void expectPostMessage(final Author member, final boolean sigValid) - throws Exception { - final BdfList signed = - BdfList.of(group.getId(), message.getTimestamp(), POST.getInt(), - member.getName(), member.getPublicKey(), - parentId == null ? null : parentId.getBytes(), - previousMsgId == null ? null : previousMsgId.getBytes(), - postContent); + private void expectPostMessage(final Author member, + final MessageId parentId, final boolean sigValid) throws Exception { + final BdfList signed = BdfList.of(group.getId(), message.getTimestamp(), + POST.getInt(), member.getName(), member.getPublicKey(), + parentId == null ? null : parentId.getBytes(), + previousMsgId.getBytes(), postContent); expectCreateAuthor(member); context.checking(new Expectations() {{ - oneOf(clientHelper) - .verifySignature(SIGNING_LABEL_POST, signature, - member.getPublicKey(), signed); + oneOf(clientHelper).verifySignature(SIGNING_LABEL_POST, signature, + member.getPublicKey(), signed); if (!sigValid) will(throwException(new GeneralSecurityException())); }}); } - private void assertMessageContext(BdfMessageContext c, Author member) - throws FormatException { + private void assertExpectedMessageContext(BdfMessageContext c, + MessageType type, Author member, + Collection dependencies) throws FormatException { BdfDictionary d = c.getDictionary(); - assertTrue(message.getTimestamp() == d.getLong(KEY_TIMESTAMP)); + assertEquals(type.getInt(), d.getLong(KEY_TYPE).intValue()); + assertEquals(message.getTimestamp(), + d.getLong(KEY_TIMESTAMP).longValue()); assertFalse(d.getBoolean(KEY_READ)); assertEquals(member.getId().getBytes(), d.getRaw(KEY_MEMBER_ID)); assertEquals(member.getName(), d.getString(KEY_MEMBER_NAME)); assertEquals(member.getPublicKey(), d.getRaw(KEY_MEMBER_PUBLIC_KEY)); - - // assert message dependencies - if (d.getLong(KEY_TYPE) == POST.getInt()) { - assertTrue(c.getDependencies().contains(previousMsgId)); - if (parentId != null) { - assertTrue(c.getDependencies().contains(parentId)); - } else { - assertFalse(c.getDependencies().contains(parentId)); - } - } else { - assertEquals(JOIN.getInt(), d.getLong(KEY_TYPE).intValue()); - } + assertEquals(dependencies, c.getDependencies()); } + @Test(expected = InvalidMessageException.class) + public void testRejectsMessageWithUnknownType() throws Exception { + BdfList body = BdfList.of(POST.getInt() + 1, memberName, memberKey, + parentId, previousMsgId, postContent, signature); + expectCreateAuthor(member); + validator.validateMessage(message, group, body); + } } From a82fdca3d4ce3066561c57e24977deb79661459c Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 29 Nov 2016 18:12:32 +0000 Subject: [PATCH 3/3] Added more private group invitation validation tests. --- .../GroupInvitationValidatorTest.java | 478 ++++++++++++------ 1 file changed, 318 insertions(+), 160 deletions(-) diff --git a/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationValidatorTest.java b/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationValidatorTest.java index 093de60f3..76ed641b4 100644 --- a/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationValidatorTest.java +++ b/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationValidatorTest.java @@ -42,199 +42,276 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { private final MessageEncoder messageEncoder = context.mock(MessageEncoder.class); - private final String groupName = "Group Name"; - private final String creatorName = "Creator Name"; + 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 = "Invitation Text"; + 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 GroupInvitationValidator validator = + private final GroupInvitationValidator validator = new GroupInvitationValidator(clientHelper, metadataEncoder, clock, authorFactory, privateGroupFactory, messageEncoder); + // INVITE Message + @Test(expected = FormatException.class) public void testRejectsTooShortInviteMessage() throws Exception { - BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName, creatorKey, salt, inviteText); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsTooLongInviteMessage() throws Exception { - BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName, creatorKey, salt, inviteText, signature, ""); - validator.validateMessage(message, group, list); + 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 list = BdfList.of(INVITE.getValue(), + BdfList body = BdfList.of(INVITE.getValue(), getRandomString(MAX_GROUP_NAME_LENGTH + 1), creatorName, creatorKey, salt, inviteText, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsInviteMessageWithEmptyGroupName() + public void testRejectsInviteMessageWithNullGroupName() throws Exception { - BdfList list = BdfList.of(INVITE.getValue(), "", creatorName, + BdfList body = BdfList.of(INVITE.getValue(), null, creatorName, creatorKey, salt, inviteText, signature); - validator.validateMessage(message, group, list); + 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 list = BdfList.of(INVITE.getValue(), groupName, + BdfList body = BdfList.of(INVITE.getValue(), groupName, getRandomString(MAX_AUTHOR_NAME_LENGTH + 1), creatorKey, salt, inviteText, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsInviteMessageWithEmptyCreatorName() + public void testRejectsInviteMessageWithNullCreatorName() throws Exception { - BdfList list = - BdfList.of(INVITE.getValue(), groupName, "", creatorKey, salt, - inviteText, signature); - validator.validateMessage(message, group, list); + 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 list = BdfList.of(INVITE.getValue(), groupName, creatorName, + BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName, getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1), salt, inviteText, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsInviteMessageWithEmptyCreatorKey() + public void testRejectsInviteMessageWithNullCreatorKey() throws Exception { - BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, - new byte[0], salt, inviteText, signature); - validator.validateMessage(message, group, list); + BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName, + null, salt, inviteText, signature); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsInviteMessageWithTooLongGroupSalt() + public void testRejectsInviteMessageWithNonRawCreatorKey() throws Exception { - BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, - creatorKey, getRandomBytes(GROUP_SALT_LENGTH + 1), inviteText, - signature); - validator.validateMessage(message, group, list); + 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 list = BdfList.of(INVITE.getValue(), groupName, creatorName, + BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName, creatorKey, getRandomBytes(GROUP_SALT_LENGTH - 1), inviteText, signature); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsInviteMessageWithTooLongMessage() + public void testRejectsInviteMessageWithTooLongGroupSalt() throws Exception { - BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + 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() + throws Exception { + 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, list); + 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() + throws Exception { + 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() + throws Exception { + 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() throws Exception { - BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName, creatorKey, salt, inviteText, getRandomBytes(MAX_SIGNATURE_LENGTH + 1)); - validator.validateMessage(message, group, list); - } - - @Test(expected = FormatException.class) - public void testRejectsInviteMessageWithEmptySignature() - throws Exception { - BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, - creatorKey, salt, inviteText, new byte[0]); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsInviteMessageWithNullSignature() throws Exception { - BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName, creatorKey, salt, inviteText, null); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsInviteMessageWithNonRawSignature() throws Exception { - BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, - creatorKey, salt, inviteText, "non raw signature"); - validator.validateMessage(message, group, list); - } - - @Test - public void testAcceptsInviteMessageWithNullMessage() - throws Exception { - expectInviteMessage(false); - BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, - creatorKey, salt, null, signature); - validator.validateMessage(message, group, list); + 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 { - expectInviteMessage(true); - BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName, creatorKey, salt, null, signature); - validator.validateMessage(message, group, list); + expectInviteMessage(true); + validator.validateMessage(message, group, body); } @Test - public void testAcceptsProperInviteMessage() - throws Exception { - expectInviteMessage(false); - BdfList list = BdfList.of(INVITE.getValue(), groupName, creatorName, + public void testAcceptsValidInviteMessage() throws Exception { + BdfList body = BdfList.of(INVITE.getValue(), groupName, creatorName, creatorKey, salt, inviteText, signature); + expectInviteMessage(false); BdfMessageContext messageContext = - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); assertTrue(messageContext.getDependencies().isEmpty()); - assertEquals(meta ,messageContext.getDictionary()); + assertEquals(meta, messageContext.getDictionary()); } private void expectInviteMessage(final boolean exception) throws Exception { - final BdfList toSign = - BdfList.of(message.getTimestamp(), message.getGroupId(), - privateGroup.getId()); + 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); + oneOf(privateGroupFactory).createPrivateGroup(groupName, creator, + salt); will(returnValue(privateGroup)); oneOf(clientHelper).verifySignature(SIGNING_LABEL_INVITE, signature, - creatorKey, toSign); - if (exception) will(throwException(new GeneralSecurityException())); - else { - oneOf(messageEncoder) - .encodeMetadata(INVITE, message.getGroupId(), - message.getTimestamp(), false, false, false, - false); + creatorKey, signed); + if (exception) { + will(throwException(new GeneralSecurityException())); + } else { + oneOf(messageEncoder).encodeMetadata(INVITE, + message.getGroupId(), message.getTimestamp(), false, + false, false, false); will(returnValue(meta)); } }}); @@ -244,181 +321,262 @@ public class GroupInvitationValidatorTest extends ValidatorTestCase { @Test(expected = FormatException.class) public void testRejectsTooShortJoinMessage() throws Exception { - BdfList list = BdfList.of(JOIN.getValue(), privateGroup.getId()); - validator.validateMessage(message, group, list); + BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId()); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsTooLongJoinMessage() throws Exception { - BdfList list = BdfList.of(JOIN.getValue(), privateGroup.getId(), + BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), previousMessageId, ""); - validator.validateMessage(message, group, list); - } - - @Test(expected = FormatException.class) - public void testRejectsJoinMessageWithTooLongGroupId() throws Exception { - BdfList list = - BdfList.of(JOIN.getValue(), getRandomBytes(GroupId.LENGTH + 1), - previousMessageId); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsJoinMessageWithTooShortGroupId() throws Exception { - BdfList list = - BdfList.of(JOIN.getValue(), getRandomBytes(GroupId.LENGTH - 1), - previousMessageId); - validator.validateMessage(message, group, list); + BdfList body = BdfList.of(JOIN.getValue(), + getRandomBytes(GroupId.LENGTH - 1), previousMessageId); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsJoinMessageWithTooLongPreviousMessageId() - throws Exception { - BdfList list = BdfList.of(JOIN.getValue(), privateGroup.getId(), - getRandomBytes(UniqueId.LENGTH + 1)); - validator.validateMessage(message, group, list); + 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 list = BdfList.of(JOIN.getValue(), privateGroup.getId(), + BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), getRandomBytes(UniqueId.LENGTH - 1)); - validator.validateMessage(message, group, list); + 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() + throws Exception { + BdfList body = BdfList.of(JOIN.getValue(), privateGroup.getId(), + "not raw"); + validator.validateMessage(message, group, body); } @Test - public void testAcceptsProperJoinMessage() + public void testAcceptsJoinMessageWithNullPreviousMessageId() throws Exception { + 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); + oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(), + message.getTimestamp(), false, false, false, false); will(returnValue(meta)); }}); - BdfList list = BdfList.of(JOIN.getValue(), privateGroup.getId(), - previousMessageId); BdfMessageContext messageContext = - validator.validateMessage(message, group, list); + 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(), + previousMessageId); + context.checking(new Expectations() {{ + oneOf(messageEncoder).encodeMetadata(JOIN, message.getGroupId(), + message.getTimestamp(), false, false, false, false); + will(returnValue(meta)); + }}); + BdfMessageContext messageContext = + validator.validateMessage(message, group, body); assertEquals(1, messageContext.getDependencies().size()); assertEquals(previousMessageId, messageContext.getDependencies().iterator().next()); - assertEquals(meta ,messageContext.getDictionary()); + assertEquals(meta, messageContext.getDictionary()); } // LEAVE message @Test(expected = FormatException.class) public void testRejectsTooShortLeaveMessage() throws Exception { - BdfList list = BdfList.of(LEAVE.getValue(), privateGroup.getId()); - validator.validateMessage(message, group, list); + BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId()); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsTooLongLeaveMessage() throws Exception { - BdfList list = BdfList.of(LEAVE.getValue(), privateGroup.getId(), + BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), previousMessageId, ""); - validator.validateMessage(message, group, list); - } - - @Test(expected = FormatException.class) - public void testRejectsLeaveMessageWithTooLongGroupId() throws Exception { - BdfList list = - BdfList.of(LEAVE.getValue(), getRandomBytes(GroupId.LENGTH + 1), - previousMessageId); - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsLeaveMessageWithTooShortGroupId() throws Exception { - BdfList list = - BdfList.of(LEAVE.getValue(), getRandomBytes(GroupId.LENGTH - 1), - previousMessageId); - validator.validateMessage(message, group, list); + BdfList body = BdfList.of(LEAVE.getValue(), + getRandomBytes(GroupId.LENGTH - 1), previousMessageId); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) - public void testRejectsLeaveMessageWithTooLongPreviousMessageId() - throws Exception { - BdfList list = BdfList.of(LEAVE.getValue(), privateGroup.getId(), - getRandomBytes(UniqueId.LENGTH + 1)); - validator.validateMessage(message, group, list); + 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 list = BdfList.of(LEAVE.getValue(), privateGroup.getId(), + BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), getRandomBytes(UniqueId.LENGTH - 1)); - validator.validateMessage(message, group, list); + 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() + throws Exception { + BdfList body = BdfList.of(LEAVE.getValue(), privateGroup.getId(), + "not raw"); + validator.validateMessage(message, group, body); } @Test - public void testAcceptsProperLeaveMessage() + public void testAcceptsLeaveMessageWithNullPreviousMessageId() throws Exception { + 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)); }}); - BdfList list = BdfList.of(LEAVE.getValue(), privateGroup.getId(), + 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, list); + validator.validateMessage(message, group, body); assertEquals(1, messageContext.getDependencies().size()); assertEquals(previousMessageId, messageContext.getDependencies().iterator().next()); - assertEquals(meta ,messageContext.getDictionary()); + assertEquals(meta, messageContext.getDictionary()); } // ABORT message @Test(expected = FormatException.class) public void testRejectsTooShortAbortMessage() throws Exception { - BdfList list = BdfList.of(ABORT.getValue()); - validator.validateMessage(message, group, list); + BdfList body = BdfList.of(ABORT.getValue()); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsTooLongAbortMessage() throws Exception { - BdfList list = BdfList.of(ABORT.getValue(), privateGroup.getId(), ""); - validator.validateMessage(message, group, list); - } - - @Test(expected = FormatException.class) - public void testRejectsAbortMessageWithTooLongGroupId() throws Exception { - BdfList list = BdfList.of(ABORT.getValue(), - getRandomBytes(GroupId.LENGTH + 1)); - validator.validateMessage(message, group, list); + BdfList body = BdfList.of(ABORT.getValue(), privateGroup.getId(), ""); + validator.validateMessage(message, group, body); } @Test(expected = FormatException.class) public void testRejectsAbortMessageWithTooShortGroupId() throws Exception { - BdfList list = BdfList.of(ABORT.getValue(), + BdfList body = BdfList.of(ABORT.getValue(), getRandomBytes(GroupId.LENGTH - 1)); - validator.validateMessage(message, group, list); + 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); } @Test - public void testAcceptsProperAbortMessage() - throws Exception { + 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 list = BdfList.of(ABORT.getValue(), privateGroup.getId()); + BdfList body = BdfList.of(ABORT.getValue(), privateGroup.getId()); BdfMessageContext messageContext = - validator.validateMessage(message, group, list); + validator.validateMessage(message, group, body); assertEquals(0, messageContext.getDependencies().size()); - assertEquals(meta ,messageContext.getDictionary()); + assertEquals(meta, messageContext.getDictionary()); } @Test(expected = FormatException.class) public void testRejectsMessageWithUnknownType() throws Exception { - BdfList list = BdfList.of(ABORT.getValue() + 1); - validator.validateMessage(message, group, list); + 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); } }