mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 19:29:06 +01:00
Methods for creating, adding and removing forums have been moved to the `ForumManager`. In order to still handle removing forums properly, a `RemoveForumHook` has been introduced. Methods for sharing forums with all current and future contacts have been removed along with the localGroup where this information was saved. The `ShareForumActivity` now has the proper label. The `SessionId` and the `ProtocolEngine` have been moved to the `clients` package. This addresses part of #322 and part of what has been discussed in #320.
358 lines
12 KiB
Java
358 lines
12 KiB
Java
package org.briarproject.introduction;
|
|
|
|
import org.briarproject.BriarTestCase;
|
|
import org.briarproject.TestUtils;
|
|
import org.briarproject.api.FormatException;
|
|
import org.briarproject.api.TransportId;
|
|
import org.briarproject.api.clients.ClientHelper;
|
|
import org.briarproject.api.data.BdfDictionary;
|
|
import org.briarproject.api.data.BdfEntry;
|
|
import org.briarproject.api.data.BdfList;
|
|
import org.briarproject.api.data.MetadataEncoder;
|
|
import org.briarproject.api.clients.SessionId;
|
|
import org.briarproject.api.sync.ClientId;
|
|
import org.briarproject.api.sync.Group;
|
|
import org.briarproject.api.sync.GroupId;
|
|
import org.briarproject.api.sync.Message;
|
|
import org.briarproject.api.sync.MessageId;
|
|
import org.briarproject.api.system.Clock;
|
|
import org.briarproject.system.SystemClock;
|
|
import org.jmock.Mockery;
|
|
import org.junit.Test;
|
|
|
|
import java.io.IOException;
|
|
|
|
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.introduction.IntroductionConstants.ACCEPT;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.E_PUBLIC_KEY;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.MSG;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.NAME;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.SESSION_ID;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.TIME;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.TRANSPORT;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.TYPE;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ABORT;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ACK;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUEST;
|
|
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
|
import static org.briarproject.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
|
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.assertFalse;
|
|
|
|
public class IntroductionValidatorTest extends BriarTestCase {
|
|
|
|
private final Mockery context = new Mockery();
|
|
private final Group group;
|
|
private final Message message;
|
|
private final IntroductionValidator validator;
|
|
private final Clock clock = new SystemClock();
|
|
|
|
public IntroductionValidatorTest() {
|
|
GroupId groupId = new GroupId(TestUtils.getRandomId());
|
|
ClientId clientId = new ClientId(TestUtils.getRandomId());
|
|
byte[] descriptor = TestUtils.getRandomBytes(12);
|
|
group = new Group(groupId, clientId, descriptor);
|
|
|
|
MessageId messageId = new MessageId(TestUtils.getRandomId());
|
|
long timestamp = System.currentTimeMillis();
|
|
byte[] raw = TestUtils.getRandomBytes(123);
|
|
message = new Message(messageId, group.getId(), timestamp, raw);
|
|
|
|
|
|
ClientHelper clientHelper = context.mock(ClientHelper.class);
|
|
MetadataEncoder metadataEncoder = context.mock(MetadataEncoder.class);
|
|
validator = new IntroductionValidator(clientHelper, metadataEncoder,
|
|
clock);
|
|
context.assertIsSatisfied();
|
|
}
|
|
|
|
//
|
|
// Introduction Requests
|
|
//
|
|
|
|
@Test
|
|
public void testValidateProperIntroductionRequest() throws IOException {
|
|
final byte[] sessionId = TestUtils.getRandomId();
|
|
final String name = TestUtils.getRandomString(MAX_AUTHOR_NAME_LENGTH);
|
|
final byte[] publicKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
|
|
final String text = TestUtils.getRandomString(MAX_MESSAGE_BODY_LENGTH);
|
|
|
|
BdfList body = BdfList.of(TYPE_REQUEST, sessionId,
|
|
name, publicKey, text);
|
|
|
|
final BdfDictionary result =
|
|
validator.validateMessage(message, group, body);
|
|
|
|
assertEquals(Long.valueOf(TYPE_REQUEST), result.getLong(TYPE));
|
|
assertEquals(sessionId, result.getRaw(SESSION_ID));
|
|
assertEquals(name, result.getString(NAME));
|
|
assertEquals(publicKey, result.getRaw(PUBLIC_KEY));
|
|
assertEquals(text, result.getString(MSG));
|
|
context.assertIsSatisfied();
|
|
}
|
|
|
|
@Test(expected = FormatException.class)
|
|
public void testValidateIntroductionRequestWithNoName() throws IOException {
|
|
BdfDictionary msg = getValidIntroductionRequest();
|
|
|
|
// no NAME is message
|
|
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID),
|
|
msg.getRaw(PUBLIC_KEY));
|
|
if (msg.containsKey(MSG)) body.add(msg.getString(MSG));
|
|
|
|
validator.validateMessage(message, group, body);
|
|
}
|
|
|
|
@Test(expected = FormatException.class)
|
|
public void testValidateIntroductionRequestWithLongName() throws IOException {
|
|
// too long NAME in message
|
|
BdfDictionary msg = getValidIntroductionRequest();
|
|
msg.put(NAME, msg.get(NAME) + "x");
|
|
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID),
|
|
msg.getString(NAME), msg.getRaw(PUBLIC_KEY));
|
|
if (msg.containsKey(MSG)) body.add(msg.getString(MSG));
|
|
|
|
validator.validateMessage(message, group, body);
|
|
}
|
|
|
|
@Test(expected = FormatException.class)
|
|
public void testValidateIntroductionRequestWithWrongType()
|
|
throws IOException {
|
|
// wrong message type
|
|
BdfDictionary msg = getValidIntroductionRequest();
|
|
msg.put(TYPE, 324234);
|
|
|
|
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID),
|
|
msg.getString(NAME), msg.getRaw(PUBLIC_KEY));
|
|
if (msg.containsKey(MSG)) body.add(msg.getString(MSG));
|
|
validator.validateMessage(message, group, body);
|
|
}
|
|
|
|
private BdfDictionary getValidIntroductionRequest() throws FormatException {
|
|
byte[] sessionId = TestUtils.getRandomId();
|
|
String name = TestUtils.getRandomString(MAX_AUTHOR_NAME_LENGTH);
|
|
byte[] publicKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
|
|
String text = TestUtils.getRandomString(MAX_MESSAGE_BODY_LENGTH);
|
|
|
|
BdfDictionary msg = new BdfDictionary();
|
|
msg.put(TYPE, TYPE_REQUEST);
|
|
msg.put(SESSION_ID, sessionId);
|
|
msg.put(NAME, name);
|
|
msg.put(PUBLIC_KEY, publicKey);
|
|
msg.put(MSG, text);
|
|
|
|
return msg;
|
|
}
|
|
|
|
//
|
|
// Introduction Responses
|
|
//
|
|
|
|
@Test
|
|
public void testValidateIntroductionAcceptResponse() throws IOException {
|
|
byte[] groupId = TestUtils.getRandomId();
|
|
byte[] sessionId = TestUtils.getRandomId();
|
|
long time = clock.currentTimeMillis();
|
|
byte[] publicKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
|
|
String transportId = TestUtils
|
|
.getRandomString(TransportId.MAX_TRANSPORT_ID_LENGTH);
|
|
BdfDictionary tProps = BdfDictionary.of(
|
|
new BdfEntry(TestUtils.getRandomString(MAX_PROPERTY_LENGTH),
|
|
TestUtils.getRandomString(MAX_PROPERTY_LENGTH))
|
|
);
|
|
BdfDictionary tp = BdfDictionary.of(
|
|
new BdfEntry(transportId, tProps)
|
|
);
|
|
|
|
BdfDictionary msg = new BdfDictionary();
|
|
msg.put(TYPE, TYPE_RESPONSE);
|
|
msg.put(GROUP_ID, groupId);
|
|
msg.put(SESSION_ID, sessionId);
|
|
msg.put(ACCEPT, true);
|
|
msg.put(TIME, time);
|
|
msg.put(E_PUBLIC_KEY, publicKey);
|
|
msg.put(TRANSPORT, tp);
|
|
|
|
BdfList body = BdfList.of(TYPE_RESPONSE, msg.getRaw(SESSION_ID),
|
|
msg.getBoolean(ACCEPT), msg.getLong(TIME),
|
|
msg.getRaw(E_PUBLIC_KEY), msg.getDictionary(TRANSPORT));
|
|
|
|
final BdfDictionary result =
|
|
validator.validateMessage(message, group, body);
|
|
|
|
assertEquals(Long.valueOf(TYPE_RESPONSE), result.getLong(TYPE));
|
|
assertEquals(sessionId, result.getRaw(SESSION_ID));
|
|
assertEquals(true, result.getBoolean(ACCEPT));
|
|
assertEquals(publicKey, result.getRaw(E_PUBLIC_KEY));
|
|
assertEquals(tp, result.getDictionary(TRANSPORT));
|
|
context.assertIsSatisfied();
|
|
}
|
|
|
|
@Test
|
|
public void testValidateIntroductionDeclineResponse()
|
|
throws IOException {
|
|
BdfDictionary msg = getValidIntroductionResponse(false);
|
|
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID),
|
|
msg.getBoolean(ACCEPT));
|
|
|
|
BdfDictionary result = validator.validateMessage(message, group, body);
|
|
|
|
assertFalse(result.getBoolean(ACCEPT));
|
|
context.assertIsSatisfied();
|
|
}
|
|
|
|
@Test(expected = FormatException.class)
|
|
public void testValidateIntroductionResponseWithoutAccept()
|
|
throws IOException {
|
|
BdfDictionary msg = getValidIntroductionResponse(false);
|
|
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID));
|
|
|
|
validator.validateMessage(message, group, body);
|
|
}
|
|
|
|
@Test(expected = FormatException.class)
|
|
public void testValidateIntroductionResponseWithBrokenTp()
|
|
throws IOException {
|
|
BdfDictionary msg = getValidIntroductionResponse(true);
|
|
BdfDictionary tp = msg.getDictionary(TRANSPORT);
|
|
tp.put(TestUtils
|
|
.getRandomString(TransportId.MAX_TRANSPORT_ID_LENGTH), "X");
|
|
msg.put(TRANSPORT, tp);
|
|
|
|
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID),
|
|
msg.getBoolean(ACCEPT), msg.getLong(TIME),
|
|
msg.getRaw(E_PUBLIC_KEY), msg.getDictionary(TRANSPORT));
|
|
|
|
validator.validateMessage(message, group, body);
|
|
}
|
|
|
|
@Test(expected = FormatException.class)
|
|
public void testValidateIntroductionResponseWithoutPublicKey()
|
|
throws IOException {
|
|
BdfDictionary msg = getValidIntroductionResponse(true);
|
|
|
|
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID),
|
|
msg.getBoolean(ACCEPT), msg.getLong(TIME),
|
|
msg.getDictionary(TRANSPORT));
|
|
|
|
validator.validateMessage(message, group, body);
|
|
}
|
|
|
|
private BdfDictionary getValidIntroductionResponse(boolean accept)
|
|
throws FormatException {
|
|
|
|
byte[] groupId = TestUtils.getRandomId();
|
|
byte[] sessionId = TestUtils.getRandomId();
|
|
long time = clock.currentTimeMillis();
|
|
byte[] publicKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
|
|
String transportId = TestUtils
|
|
.getRandomString(TransportId.MAX_TRANSPORT_ID_LENGTH);
|
|
BdfDictionary tProps = BdfDictionary.of(
|
|
new BdfEntry(TestUtils.getRandomString(MAX_PROPERTY_LENGTH),
|
|
TestUtils.getRandomString(MAX_PROPERTY_LENGTH))
|
|
);
|
|
BdfDictionary tp = BdfDictionary.of(
|
|
new BdfEntry(transportId, tProps)
|
|
);
|
|
|
|
BdfDictionary msg = new BdfDictionary();
|
|
msg.put(TYPE, TYPE_RESPONSE);
|
|
msg.put(GROUP_ID, groupId);
|
|
msg.put(SESSION_ID, sessionId);
|
|
msg.put(ACCEPT, accept);
|
|
if (accept) {
|
|
msg.put(TIME, time);
|
|
msg.put(E_PUBLIC_KEY, publicKey);
|
|
msg.put(TRANSPORT, tp);
|
|
}
|
|
|
|
return msg;
|
|
}
|
|
|
|
//
|
|
// Introduction ACK
|
|
//
|
|
|
|
@Test
|
|
public void testValidateProperIntroductionAck() throws IOException {
|
|
final byte[] sessionId = TestUtils.getRandomId();
|
|
|
|
BdfDictionary msg = new BdfDictionary();
|
|
msg.put(TYPE, TYPE_ACK);
|
|
msg.put(SESSION_ID, sessionId);
|
|
|
|
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID));
|
|
|
|
BdfDictionary result =
|
|
validator.validateMessage(message, group, body);
|
|
|
|
assertEquals(Long.valueOf(TYPE_ACK), result.getLong(TYPE));
|
|
assertEquals(sessionId, result.getRaw(SESSION_ID));
|
|
context.assertIsSatisfied();
|
|
}
|
|
|
|
@Test(expected = FormatException.class)
|
|
public void testValidateTooLongIntroductionAck() throws IOException {
|
|
BdfDictionary msg = BdfDictionary.of(
|
|
new BdfEntry(TYPE, TYPE_ACK),
|
|
new BdfEntry(SESSION_ID, TestUtils.getRandomId()),
|
|
new BdfEntry("garbage", TestUtils.getRandomString(255))
|
|
);
|
|
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID),
|
|
msg.getString("garbage"));
|
|
|
|
validator.validateMessage(message, group, body);
|
|
}
|
|
|
|
@Test(expected = FormatException.class)
|
|
public void testValidateIntroductionAckWithLongSessionId() throws IOException {
|
|
BdfDictionary msg = BdfDictionary.of(
|
|
new BdfEntry(TYPE, TYPE_ACK),
|
|
new BdfEntry(SESSION_ID, new byte[SessionId.LENGTH + 1])
|
|
);
|
|
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID));
|
|
|
|
validator.validateMessage(message, group, body);
|
|
}
|
|
|
|
//
|
|
// Introduction Abort
|
|
//
|
|
|
|
@Test
|
|
public void testValidateProperIntroductionAbort() throws IOException {
|
|
byte[] sessionId = TestUtils.getRandomId();
|
|
|
|
BdfDictionary msg = new BdfDictionary();
|
|
msg.put(TYPE, TYPE_ABORT);
|
|
msg.put(SESSION_ID, sessionId);
|
|
|
|
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID));
|
|
|
|
BdfDictionary result =
|
|
validator.validateMessage(message, group, body);
|
|
|
|
assertEquals(Long.valueOf(TYPE_ABORT), result.getLong(TYPE));
|
|
assertEquals(sessionId, result.getRaw(SESSION_ID));
|
|
context.assertIsSatisfied();
|
|
}
|
|
|
|
@Test(expected = FormatException.class)
|
|
public void testValidateTooLongIntroductionAbort() throws IOException {
|
|
BdfDictionary msg = BdfDictionary.of(
|
|
new BdfEntry(TYPE, TYPE_ABORT),
|
|
new BdfEntry(SESSION_ID, TestUtils.getRandomId()),
|
|
new BdfEntry("garbage", TestUtils.getRandomString(255))
|
|
);
|
|
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID),
|
|
msg.getString("garbage"));
|
|
|
|
validator.validateMessage(message, group, body);
|
|
}
|
|
|
|
}
|