mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 12:19:54 +01:00
Helper methods for parsing transport properties.
This commit is contained in:
@@ -7,6 +7,7 @@ import org.briarproject.bramble.api.db.DbException;
|
|||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
@@ -103,4 +104,7 @@ public interface ClientHelper {
|
|||||||
BdfList signed) throws FormatException, GeneralSecurityException;
|
BdfList signed) throws FormatException, GeneralSecurityException;
|
||||||
|
|
||||||
Author parseAndValidateAuthor(BdfList author) throws FormatException;
|
Author parseAndValidateAuthor(BdfList author) throws FormatException;
|
||||||
|
|
||||||
|
TransportProperties parseAndValidateTransportProperties(
|
||||||
|
BdfDictionary properties) throws FormatException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.briarproject.bramble.api.db.Transaction;
|
|||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.AuthorFactory;
|
import org.briarproject.bramble.api.identity.AuthorFactory;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
@@ -37,6 +38,8 @@ import javax.inject.Inject;
|
|||||||
import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION;
|
import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
|
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
|
||||||
|
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
||||||
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
||||||
@@ -382,4 +385,18 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
checkLength(publicKey, 1, MAX_PUBLIC_KEY_LENGTH);
|
checkLength(publicKey, 1, MAX_PUBLIC_KEY_LENGTH);
|
||||||
return authorFactory.createAuthor(formatVersion, name, publicKey);
|
return authorFactory.createAuthor(formatVersion, name, publicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransportProperties parseAndValidateTransportProperties(
|
||||||
|
BdfDictionary properties) throws FormatException {
|
||||||
|
checkSize(properties, 0, MAX_PROPERTIES_PER_TRANSPORT);
|
||||||
|
TransportProperties p = new TransportProperties();
|
||||||
|
for (String key : properties.keySet()) {
|
||||||
|
checkLength(key, 0, MAX_PROPERTY_LENGTH);
|
||||||
|
String value = properties.getString(key);
|
||||||
|
checkLength(value, 0, MAX_PROPERTY_LENGTH);
|
||||||
|
p.put(key, value);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -347,10 +347,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
|||||||
throws FormatException {
|
throws FormatException {
|
||||||
// Transport ID, version, properties
|
// Transport ID, version, properties
|
||||||
BdfDictionary dictionary = message.getDictionary(2);
|
BdfDictionary dictionary = message.getDictionary(2);
|
||||||
TransportProperties p = new TransportProperties();
|
return clientHelper.parseAndValidateTransportProperties(dictionary);
|
||||||
for (String key : dictionary.keySet())
|
|
||||||
p.put(key, dictionary.getString(key));
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LatestUpdate {
|
private static class LatestUpdate {
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ import org.briarproject.bramble.api.system.Clock;
|
|||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.plugin.TransportId.MAX_TRANSPORT_ID_LENGTH;
|
import static org.briarproject.bramble.api.plugin.TransportId.MAX_TRANSPORT_ID_LENGTH;
|
||||||
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
|
|
||||||
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
|
||||||
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
||||||
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
||||||
|
|
||||||
@@ -42,12 +40,7 @@ class TransportPropertyValidator extends BdfMessageValidator {
|
|||||||
if (version < 0) throw new FormatException();
|
if (version < 0) throw new FormatException();
|
||||||
// Properties
|
// Properties
|
||||||
BdfDictionary dictionary = body.getDictionary(2);
|
BdfDictionary dictionary = body.getDictionary(2);
|
||||||
checkSize(dictionary, 0, MAX_PROPERTIES_PER_TRANSPORT);
|
clientHelper.parseAndValidateTransportProperties(dictionary);
|
||||||
for (String key : dictionary.keySet()) {
|
|
||||||
checkLength(key, 0, MAX_PROPERTY_LENGTH);
|
|
||||||
String value = dictionary.getString(key);
|
|
||||||
checkLength(value, 0, MAX_PROPERTY_LENGTH);
|
|
||||||
}
|
|
||||||
// Return the metadata
|
// Return the metadata
|
||||||
BdfDictionary meta = new BdfDictionary();
|
BdfDictionary meta = new BdfDictionary();
|
||||||
meta.put("transportId", transportId);
|
meta.put("transportId", transportId);
|
||||||
|
|||||||
@@ -400,6 +400,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(messageMetadata));
|
will(returnValue(messageMetadata));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
|
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
|
||||||
will(returnValue(fooUpdate));
|
will(returnValue(fooUpdate));
|
||||||
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
|
fooPropertiesDict);
|
||||||
|
will(returnValue(fooProperties));
|
||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
oneOf(db).endTransaction(txn);
|
oneOf(db).endTransaction(txn);
|
||||||
}});
|
}});
|
||||||
@@ -467,6 +470,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(messageMetadata3));
|
will(returnValue(messageMetadata3));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
|
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
|
||||||
will(returnValue(fooUpdate));
|
will(returnValue(fooUpdate));
|
||||||
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
|
fooPropertiesDict);
|
||||||
|
will(returnValue(fooProperties));
|
||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
oneOf(db).endTransaction(txn);
|
oneOf(db).endTransaction(txn);
|
||||||
}});
|
}});
|
||||||
@@ -502,6 +508,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(messageMetadata));
|
will(returnValue(messageMetadata));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, updateId);
|
oneOf(clientHelper).getMessageAsList(txn, updateId);
|
||||||
will(returnValue(update));
|
will(returnValue(update));
|
||||||
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
|
fooPropertiesDict);
|
||||||
|
will(returnValue(fooProperties));
|
||||||
// Properties are unchanged so we're done
|
// Properties are unchanged so we're done
|
||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
oneOf(db).endTransaction(txn);
|
oneOf(db).endTransaction(txn);
|
||||||
@@ -562,9 +571,12 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
MessageId contactGroupUpdateId = new MessageId(getRandomId());
|
MessageId contactGroupUpdateId = new MessageId(getRandomId());
|
||||||
Map<MessageId, BdfDictionary> contactGroupMessageMetadata =
|
Map<MessageId, BdfDictionary> contactGroupMessageMetadata =
|
||||||
Collections.singletonMap(contactGroupUpdateId, oldMetadata);
|
Collections.singletonMap(contactGroupUpdateId, oldMetadata);
|
||||||
BdfList oldUpdate = BdfList.of("foo", 1, BdfDictionary.of(
|
TransportProperties oldProperties = new TransportProperties();
|
||||||
|
oldProperties.put("fooKey1", "oldFooValue1");
|
||||||
|
BdfDictionary oldPropertiesDict = BdfDictionary.of(
|
||||||
new BdfEntry("fooKey1", "oldFooValue1")
|
new BdfEntry("fooKey1", "oldFooValue1")
|
||||||
));
|
);
|
||||||
|
BdfList oldUpdate = BdfList.of("foo", 1, oldPropertiesDict);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(db).startTransaction(false);
|
oneOf(db).startTransaction(false);
|
||||||
@@ -575,6 +587,9 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(localGroupMessageMetadata));
|
will(returnValue(localGroupMessageMetadata));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId);
|
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId);
|
||||||
will(returnValue(oldUpdate));
|
will(returnValue(oldUpdate));
|
||||||
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
|
oldPropertiesDict);
|
||||||
|
will(returnValue(oldProperties));
|
||||||
// Store the merged properties in the local group, version 2
|
// Store the merged properties in the local group, version 2
|
||||||
expectStoreMessage(txn, localGroup.getId(), "foo",
|
expectStoreMessage(txn, localGroup.getId(), "foo",
|
||||||
fooPropertiesDict, 2, true, false);
|
fooPropertiesDict, 2, true, false);
|
||||||
@@ -638,8 +653,14 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Retrieve and parse the latest local properties
|
// Retrieve and parse the latest local properties
|
||||||
oneOf(clientHelper).getMessageAsList(txn, fooVersion999);
|
oneOf(clientHelper).getMessageAsList(txn, fooVersion999);
|
||||||
will(returnValue(fooUpdate));
|
will(returnValue(fooUpdate));
|
||||||
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
|
fooPropertiesDict);
|
||||||
|
will(returnValue(fooProperties));
|
||||||
oneOf(clientHelper).getMessageAsList(txn, barVersion3);
|
oneOf(clientHelper).getMessageAsList(txn, barVersion3);
|
||||||
will(returnValue(barUpdate));
|
will(returnValue(barUpdate));
|
||||||
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
|
barPropertiesDict);
|
||||||
|
will(returnValue(barProperties));
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,78 +3,78 @@ package org.briarproject.bramble.properties;
|
|||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.client.ClientHelper;
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||||
|
import org.briarproject.bramble.api.data.BdfEntry;
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.api.data.MetadataEncoder;
|
import org.briarproject.bramble.api.data.MetadataEncoder;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.api.sync.Group;
|
import org.briarproject.bramble.api.sync.Group;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.jmock.Expectations;
|
||||||
import org.jmock.Mockery;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.plugin.TransportId.MAX_TRANSPORT_ID_LENGTH;
|
import static org.briarproject.bramble.api.plugin.TransportId.MAX_TRANSPORT_ID_LENGTH;
|
||||||
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getClientId;
|
import static org.briarproject.bramble.test.TestUtils.getClientId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
public class TransportPropertyValidatorTest extends BrambleTestCase {
|
public class TransportPropertyValidatorTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
|
private final ClientHelper clientHelper = context.mock(ClientHelper.class);
|
||||||
|
|
||||||
private final TransportId transportId;
|
private final TransportId transportId;
|
||||||
private final BdfDictionary bdfDictionary;
|
private final BdfDictionary bdfDictionary;
|
||||||
|
private final TransportProperties transportProperties;
|
||||||
private final Group group;
|
private final Group group;
|
||||||
private final Message message;
|
private final Message message;
|
||||||
private final TransportPropertyValidator tpv;
|
private final TransportPropertyValidator tpv;
|
||||||
|
|
||||||
public TransportPropertyValidatorTest() {
|
public TransportPropertyValidatorTest() {
|
||||||
transportId = getTransportId();
|
transportId = getTransportId();
|
||||||
bdfDictionary = new BdfDictionary();
|
bdfDictionary = BdfDictionary.of(new BdfEntry("foo", "bar"));
|
||||||
|
transportProperties = new TransportProperties();
|
||||||
|
transportProperties.put("foo", "bar");
|
||||||
|
|
||||||
group = getGroup(getClientId());
|
group = getGroup(getClientId());
|
||||||
MessageId messageId = new MessageId(getRandomId());
|
message = getMessage(group.getId());
|
||||||
long timestamp = System.currentTimeMillis();
|
|
||||||
byte[] body = getRandomBytes(123);
|
|
||||||
message = new Message(messageId, group.getId(), timestamp, body);
|
|
||||||
|
|
||||||
Mockery context = new Mockery();
|
|
||||||
ClientHelper clientHelper = context.mock(ClientHelper.class);
|
|
||||||
MetadataEncoder metadataEncoder = context.mock(MetadataEncoder.class);
|
MetadataEncoder metadataEncoder = context.mock(MetadataEncoder.class);
|
||||||
Clock clock = context.mock(Clock.class);
|
Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
tpv = new TransportPropertyValidator(clientHelper, metadataEncoder,
|
tpv = new TransportPropertyValidator(clientHelper, metadataEncoder,
|
||||||
clock);
|
clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidateProperMessage() throws IOException {
|
public void testValidateProperMessage() throws IOException {
|
||||||
|
|
||||||
BdfList body = BdfList.of(transportId.getString(), 4, bdfDictionary);
|
BdfList body = BdfList.of(transportId.getString(), 4, bdfDictionary);
|
||||||
|
|
||||||
BdfDictionary result = tpv.validateMessage(message, group, body)
|
context.checking(new Expectations() {{
|
||||||
.getDictionary();
|
oneOf(clientHelper).parseAndValidateTransportProperties(
|
||||||
|
bdfDictionary);
|
||||||
|
will(returnValue(transportProperties));
|
||||||
|
}});
|
||||||
|
|
||||||
|
BdfDictionary result =
|
||||||
|
tpv.validateMessage(message, group, body).getDictionary();
|
||||||
assertEquals(transportId.getString(), result.getString("transportId"));
|
assertEquals(transportId.getString(), result.getString("transportId"));
|
||||||
assertEquals(4, result.getLong("version").longValue());
|
assertEquals(4, result.getLong("version").longValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testValidateWrongVersionValue() throws IOException {
|
public void testValidateWrongVersionValue() throws IOException {
|
||||||
|
|
||||||
BdfList body = BdfList.of(transportId.getString(), -1, bdfDictionary);
|
BdfList body = BdfList.of(transportId.getString(), -1, bdfDictionary);
|
||||||
tpv.validateMessage(message, group, body);
|
tpv.validateMessage(message, group, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testValidateWrongVersionType() throws IOException {
|
public void testValidateWrongVersionType() throws IOException {
|
||||||
|
|
||||||
BdfList body = BdfList.of(transportId.getString(), bdfDictionary,
|
BdfList body = BdfList.of(transportId.getString(), bdfDictionary,
|
||||||
bdfDictionary);
|
bdfDictionary);
|
||||||
tpv.validateMessage(message, group, body);
|
tpv.validateMessage(message, group, body);
|
||||||
@@ -82,27 +82,15 @@ public class TransportPropertyValidatorTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testValidateLongTransportId() throws IOException {
|
public void testValidateLongTransportId() throws IOException {
|
||||||
|
|
||||||
String wrongTransportIdString =
|
String wrongTransportIdString =
|
||||||
StringUtils.getRandomString(MAX_TRANSPORT_ID_LENGTH + 1);
|
getRandomString(MAX_TRANSPORT_ID_LENGTH + 1);
|
||||||
BdfList body = BdfList.of(wrongTransportIdString, 4, bdfDictionary);
|
BdfList body = BdfList.of(wrongTransportIdString, 4, bdfDictionary);
|
||||||
tpv.validateMessage(message, group, body);
|
tpv.validateMessage(message, group, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testValidateEmptyTransportId() throws IOException {
|
public void testValidateEmptyTransportId() throws IOException {
|
||||||
|
|
||||||
BdfList body = BdfList.of("", 4, bdfDictionary);
|
BdfList body = BdfList.of("", 4, bdfDictionary);
|
||||||
tpv.validateMessage(message, group, body);
|
tpv.validateMessage(message, group, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
|
||||||
public void testValidateTooManyProperties() throws IOException {
|
|
||||||
|
|
||||||
BdfDictionary d = new BdfDictionary();
|
|
||||||
for (int i = 0; i < MAX_PROPERTIES_PER_TRANSPORT + 1; i++)
|
|
||||||
d.put(String.valueOf(i), i);
|
|
||||||
BdfList body = BdfList.of(transportId.getString(), 4, d);
|
|
||||||
tpv.validateMessage(message, group, body);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user