From cc7ffee28d368fc026c5721ce467317d2908ed96 Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Mon, 29 Feb 2016 21:57:02 +0000 Subject: [PATCH] Superclass for validating messages that are BDF lists. --- .../clients/BdfMessageValidator.java | 114 ++++++++++ .../forum/ForumListValidator.java | 82 +++----- .../org/briarproject/forum/ForumModule.java | 24 +-- .../forum/ForumPostValidator.java | 194 +++++++----------- .../messaging/MessagingModule.java | 6 +- .../messaging/PrivateMessageValidator.java | 92 +++------ .../properties/PropertiesModule.java | 6 +- .../TransportPropertyValidator.java | 94 +++------ 8 files changed, 290 insertions(+), 322 deletions(-) create mode 100644 briar-core/src/org/briarproject/clients/BdfMessageValidator.java diff --git a/briar-core/src/org/briarproject/clients/BdfMessageValidator.java b/briar-core/src/org/briarproject/clients/BdfMessageValidator.java new file mode 100644 index 0000000000..fd170aa7c8 --- /dev/null +++ b/briar-core/src/org/briarproject/clients/BdfMessageValidator.java @@ -0,0 +1,114 @@ +package org.briarproject.clients; + +import org.briarproject.api.FormatException; +import org.briarproject.api.clients.ClientHelper; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.data.BdfList; +import org.briarproject.api.data.MetadataEncoder; +import org.briarproject.api.db.Metadata; +import org.briarproject.api.sync.Group; +import org.briarproject.api.sync.Message; +import org.briarproject.api.sync.MessageValidator; +import org.briarproject.api.system.Clock; +import org.briarproject.util.StringUtils; + +import java.util.logging.Logger; + +import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; +import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; + +public abstract class BdfMessageValidator implements MessageValidator { + + protected static final Logger LOG = + Logger.getLogger(BdfMessageValidator.class.getName()); + + protected final ClientHelper clientHelper; + protected final MetadataEncoder metadataEncoder; + protected final Clock clock; + + protected BdfMessageValidator(ClientHelper clientHelper, + MetadataEncoder metadataEncoder, Clock clock) { + this.clientHelper = clientHelper; + this.metadataEncoder = metadataEncoder; + this.clock = clock; + } + + protected abstract BdfDictionary validateMessage(BdfList message, Group g, + long timestamp) throws FormatException; + + @Override + public Metadata validateMessage(Message m, Group g) { + // Reject the message if it's too far in the future + long now = clock.currentTimeMillis(); + if (m.getTimestamp() - now > MAX_CLOCK_DIFFERENCE) { + LOG.info("Timestamp is too far in the future"); + return null; + } + byte[] raw = m.getRaw(); + try { + BdfList message = clientHelper.toList(raw, MESSAGE_HEADER_LENGTH, + raw.length - MESSAGE_HEADER_LENGTH); + BdfDictionary meta = validateMessage(message, g, m.getTimestamp()); + if (meta == null) { + LOG.info("Invalid message"); + return null; + } + return metadataEncoder.encode(meta); + } catch (FormatException e) { + LOG.info("Invalid message"); + return null; + } + } + + protected void checkLength(String s, int minLength, int maxLength) + throws FormatException { + if (s != null) { + int length = StringUtils.toUtf8(s).length; + if (length < minLength) throw new FormatException(); + if (length > maxLength) throw new FormatException(); + } + } + + protected void checkLength(String s, int length) throws FormatException { + if (s != null && StringUtils.toUtf8(s).length != length) + throw new FormatException(); + } + + protected void checkLength(byte[] b, int minLength, int maxLength) + throws FormatException { + if (b != null) { + if (b.length < minLength) throw new FormatException(); + if (b.length > maxLength) throw new FormatException(); + } + } + + protected void checkLength(byte[] b, int length) throws FormatException { + if (b != null && b.length != length) throw new FormatException(); + } + + protected void checkSize(BdfList list, int minSize, int maxSize) + throws FormatException { + if (list != null) { + if (list.size() < minSize) throw new FormatException(); + if (list.size() > maxSize) throw new FormatException(); + } + } + + protected void checkSize(BdfList list, int size) throws FormatException { + if (list != null && list.size() != size) throw new FormatException(); + } + + protected void checkSize(BdfDictionary dictionary, int minSize, + int maxSize) throws FormatException { + if (dictionary != null) { + if (dictionary.size() < minSize) throw new FormatException(); + if (dictionary.size() > maxSize) throw new FormatException(); + } + } + + protected void checkSize(BdfDictionary dictionary, int size) + throws FormatException { + if (dictionary != null && dictionary.size() != size) + throw new FormatException(); + } +} diff --git a/briar-core/src/org/briarproject/forum/ForumListValidator.java b/briar-core/src/org/briarproject/forum/ForumListValidator.java index 0a8e04e322..e4b6e4edc6 100644 --- a/briar-core/src/org/briarproject/forum/ForumListValidator.java +++ b/briar-core/src/org/briarproject/forum/ForumListValidator.java @@ -1,69 +1,47 @@ package org.briarproject.forum; import org.briarproject.api.FormatException; +import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.data.BdfDictionary; -import org.briarproject.api.data.BdfReader; -import org.briarproject.api.data.BdfReaderFactory; +import org.briarproject.api.data.BdfList; import org.briarproject.api.data.MetadataEncoder; -import org.briarproject.api.db.Metadata; import org.briarproject.api.sync.Group; -import org.briarproject.api.sync.Message; -import org.briarproject.api.sync.MessageValidator; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.logging.Logger; +import org.briarproject.api.system.Clock; +import org.briarproject.clients.BdfMessageValidator; import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH; import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH; -import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; - -class ForumListValidator implements MessageValidator { - - private static final Logger LOG = - Logger.getLogger(ForumListValidator.class.getName()); - private final BdfReaderFactory bdfReaderFactory; - private final MetadataEncoder metadataEncoder; +class ForumListValidator extends BdfMessageValidator { - ForumListValidator(BdfReaderFactory bdfReaderFactory, - MetadataEncoder metadataEncoder) { - this.bdfReaderFactory = bdfReaderFactory; - this.metadataEncoder = metadataEncoder; + ForumListValidator(ClientHelper clientHelper, + MetadataEncoder metadataEncoder, Clock clock) { + super(clientHelper, metadataEncoder, clock); } @Override - public Metadata validateMessage(Message m, Group g) { - try { - // Parse the message body - byte[] raw = m.getRaw(); - ByteArrayInputStream in = new ByteArrayInputStream(raw, - MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH); - BdfReader r = bdfReaderFactory.createReader(in); - r.readListStart(); - long version = r.readLong(); - if (version < 0) throw new FormatException(); - r.readListStart(); - while (!r.hasListEnd()) { - r.readListStart(); - String name = r.readString(MAX_FORUM_NAME_LENGTH); - if (name.length() == 0) throw new FormatException(); - byte[] salt = r.readRaw(FORUM_SALT_LENGTH); - if (salt.length != FORUM_SALT_LENGTH) - throw new FormatException(); - r.readListEnd(); - } - r.readListEnd(); - r.readListEnd(); - if (!r.eof()) throw new FormatException(); - // Return the metadata - BdfDictionary d = new BdfDictionary(); - d.put("version", version); - d.put("local", false); - return metadataEncoder.encode(d); - } catch (IOException e) { - LOG.info("Invalid forum list"); - return null; + public BdfDictionary validateMessage(BdfList message, Group g, + long timestamp) throws FormatException { + // Version, forum list + checkSize(message, 2); + // Version + long version = message.getLong(0); + if (version < 0) throw new FormatException(); + // Forum list + BdfList forumList = message.getList(1); + for (int i = 0; i < forumList.size(); i++) { + BdfList forum = forumList.getList(i); + // Name, salt + checkSize(forum, 2); + String name = forum.getString(0); + checkLength(name, 1, MAX_FORUM_NAME_LENGTH); + byte[] salt = forum.getRaw(1); + checkLength(salt, FORUM_SALT_LENGTH); } + // Return the metadata + BdfDictionary meta = new BdfDictionary(); + meta.put("version", version); + meta.put("local", false); + return meta; } } diff --git a/briar-core/src/org/briarproject/forum/ForumModule.java b/briar-core/src/org/briarproject/forum/ForumModule.java index caa066d344..56c18546f8 100644 --- a/briar-core/src/org/briarproject/forum/ForumModule.java +++ b/briar-core/src/org/briarproject/forum/ForumModule.java @@ -3,16 +3,14 @@ package org.briarproject.forum; import com.google.inject.AbstractModule; import com.google.inject.Provides; +import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.crypto.CryptoComponent; -import org.briarproject.api.data.BdfReaderFactory; -import org.briarproject.api.data.BdfWriterFactory; import org.briarproject.api.data.MetadataEncoder; -import org.briarproject.api.data.ObjectReader; import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumPostFactory; import org.briarproject.api.forum.ForumSharingManager; -import org.briarproject.api.identity.Author; +import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.sync.ValidationManager; import org.briarproject.api.system.Clock; @@ -29,13 +27,10 @@ public class ForumModule extends AbstractModule { @Provides @Singleton ForumPostValidator getForumPostValidator( ValidationManager validationManager, CryptoComponent crypto, - BdfReaderFactory bdfReaderFactory, - BdfWriterFactory bdfWriterFactory, - ObjectReader<Author> authorReader, MetadataEncoder metadataEncoder, - Clock clock) { + AuthorFactory authorFactory, ClientHelper clientHelper, + MetadataEncoder metadataEncoder, Clock clock) { ForumPostValidator validator = new ForumPostValidator(crypto, - bdfReaderFactory, bdfWriterFactory, authorReader, - metadataEncoder, clock); + authorFactory, clientHelper, metadataEncoder, clock); validationManager.registerMessageValidator( ForumManagerImpl.CLIENT_ID, validator); return validator; @@ -43,11 +38,10 @@ public class ForumModule extends AbstractModule { @Provides @Singleton ForumListValidator getForumListValidator( - ValidationManager validationManager, - BdfReaderFactory bdfReaderFactory, - MetadataEncoder metadataEncoder) { - ForumListValidator validator = new ForumListValidator(bdfReaderFactory, - metadataEncoder); + ValidationManager validationManager, ClientHelper clientHelper, + MetadataEncoder metadataEncoder, Clock clock) { + ForumListValidator validator = new ForumListValidator(clientHelper, + metadataEncoder, clock); validationManager.registerMessageValidator( ForumSharingManagerImpl.CLIENT_ID, validator); return validator; diff --git a/briar-core/src/org/briarproject/forum/ForumPostValidator.java b/briar-core/src/org/briarproject/forum/ForumPostValidator.java index 3fbcf2f08f..4ea87c11f6 100644 --- a/briar-core/src/org/briarproject/forum/ForumPostValidator.java +++ b/briar-core/src/org/briarproject/forum/ForumPostValidator.java @@ -2,164 +2,114 @@ package org.briarproject.forum; import org.briarproject.api.FormatException; import org.briarproject.api.UniqueId; +import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.KeyParser; import org.briarproject.api.crypto.PublicKey; import org.briarproject.api.crypto.Signature; import org.briarproject.api.data.BdfDictionary; -import org.briarproject.api.data.BdfReader; -import org.briarproject.api.data.BdfReaderFactory; -import org.briarproject.api.data.BdfWriter; -import org.briarproject.api.data.BdfWriterFactory; +import org.briarproject.api.data.BdfList; import org.briarproject.api.data.MetadataEncoder; -import org.briarproject.api.data.ObjectReader; -import org.briarproject.api.db.Metadata; import org.briarproject.api.identity.Author; +import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.sync.Group; -import org.briarproject.api.sync.Message; -import org.briarproject.api.sync.MessageId; -import org.briarproject.api.sync.MessageValidator; import org.briarproject.api.system.Clock; +import org.briarproject.clients.BdfMessageValidator; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.security.GeneralSecurityException; -import java.util.logging.Logger; import static org.briarproject.api.forum.ForumConstants.MAX_CONTENT_TYPE_LENGTH; import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH; +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.sync.SyncConstants.MESSAGE_HEADER_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; -class ForumPostValidator implements MessageValidator { - - private static final Logger LOG = - Logger.getLogger(ForumPostValidator.class.getName()); +class ForumPostValidator extends BdfMessageValidator { private final CryptoComponent crypto; - private final BdfReaderFactory bdfReaderFactory; - private final BdfWriterFactory bdfWriterFactory; - private final ObjectReader<Author> authorReader; - private final MetadataEncoder metadataEncoder; - private final Clock clock; - private final KeyParser keyParser; + private final AuthorFactory authorFactory; - ForumPostValidator(CryptoComponent crypto, - BdfReaderFactory bdfReaderFactory, - BdfWriterFactory bdfWriterFactory, - ObjectReader<Author> authorReader, - MetadataEncoder metadataEncoder, Clock clock) { + ForumPostValidator(CryptoComponent crypto, AuthorFactory authorFactory, + ClientHelper clientHelper, MetadataEncoder metadataEncoder, + Clock clock) { + super(clientHelper, metadataEncoder, clock); this.crypto = crypto; - this.bdfReaderFactory = bdfReaderFactory; - this.bdfWriterFactory = bdfWriterFactory; - this.authorReader = authorReader; - this.metadataEncoder = metadataEncoder; - this.clock = clock; - keyParser = crypto.getSignatureKeyParser(); + this.authorFactory = authorFactory; } @Override - public Metadata validateMessage(Message m, Group g) { - // Reject the message if it's too far in the future - long now = clock.currentTimeMillis(); - if (m.getTimestamp() - now > MAX_CLOCK_DIFFERENCE) { - LOG.info("Timestamp is too far in the future"); + protected BdfDictionary validateMessage(BdfList message, Group g, + long timestamp) throws FormatException { + // Parent ID, author, content type, forum post body, signature + checkSize(message, 5); + // Parent ID is optional + byte[] parent = message.getOptionalRaw(0); + checkLength(parent, UniqueId.LENGTH); + // Author is optional + Author author = null; + BdfList authorList = message.getOptionalList(1); + if (authorList != null) { + // Name, public key + checkSize(authorList, 2); + String name = authorList.getString(0); + checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH); + byte[] publicKey = authorList.getRaw(1); + checkLength(publicKey, 0, MAX_PUBLIC_KEY_LENGTH); + author = authorFactory.createAuthor(name, publicKey); + } + // Content type + String contentType = message.getString(2); + checkLength(contentType, 0, MAX_CONTENT_TYPE_LENGTH); + // Forum post body + byte[] body = message.getRaw(3); + checkLength(body, 0, MAX_FORUM_POST_BODY_LENGTH); + // Signature is optional + byte[] sig = message.getOptionalRaw(4); + checkLength(sig, 0, MAX_SIGNATURE_LENGTH); + // If there's an author there must be a signature and vice versa + if (author != null && sig == null) { + LOG.info("Author without signature"); return null; } - try { - // Parse the message body - byte[] raw = m.getRaw(); - ByteArrayInputStream in = new ByteArrayInputStream(raw, - MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH); - BdfReader r = bdfReaderFactory.createReader(in); - MessageId parent = null; - Author author = null; - byte[] sig = null; - r.readListStart(); - // Read the parent ID, if any - if (r.hasRaw()) { - byte[] id = r.readRaw(UniqueId.LENGTH); - if (id.length < UniqueId.LENGTH) throw new FormatException(); - parent = new MessageId(id); - } else { - r.readNull(); - } - // Read the author, if any - if (r.hasList()) author = authorReader.readObject(r); - else r.readNull(); - // Read the content type - String contentType = r.readString(MAX_CONTENT_TYPE_LENGTH); - // Read the forum post body - byte[] postBody = r.readRaw(MAX_FORUM_POST_BODY_LENGTH); - - // Read the signature, if any - if (r.hasRaw()) sig = r.readRaw(MAX_SIGNATURE_LENGTH); - else r.readNull(); - r.readListEnd(); - if (!r.eof()) throw new FormatException(); - // If there's an author there must be a signature and vice versa - if (author != null && sig == null) { - LOG.info("Author without signature"); - return null; - } - if (author == null && sig != null) { - LOG.info("Signature without author"); - return null; - } - // Verify the signature, if any - if (author != null) { + if (author == null && sig != null) { + LOG.info("Signature without author"); + return null; + } + // Verify the signature, if any + if (author != null) { + try { // Parse the public key + KeyParser keyParser = crypto.getSignatureKeyParser(); PublicKey key = keyParser.parsePublicKey(author.getPublicKey()); // Serialise the data to be signed - ByteArrayOutputStream out = new ByteArrayOutputStream(); - BdfWriter w = bdfWriterFactory.createWriter(out); - w.writeListStart(); - w.writeRaw(m.getGroupId().getBytes()); - w.writeLong(m.getTimestamp()); - if (parent == null) w.writeNull(); - else w.writeRaw(parent.getBytes()); - writeAuthor(w, author); - w.writeString(contentType); - w.writeRaw(postBody); - w.writeListEnd(); + BdfList signed = BdfList.of(g.getId(), timestamp, parentId, + authorList, contentType, body); // Verify the signature Signature signature = crypto.getSignature(); signature.initVerify(key); - signature.update(out.toByteArray()); + signature.update(clientHelper.toByteArray(signed)); if (!signature.verify(sig)) { LOG.info("Invalid signature"); return null; } + } catch (GeneralSecurityException e) { + LOG.info("Invalid public key"); + return null; } - // Return the metadata - BdfDictionary d = new BdfDictionary(); - d.put("timestamp", m.getTimestamp()); - if (parent != null) d.put("parent", parent.getBytes()); - if (author != null) { - BdfDictionary d1 = new BdfDictionary(); - d1.put("id", author.getId().getBytes()); - d1.put("name", author.getName()); - d1.put("publicKey", author.getPublicKey()); - d.put("author", d1); - } - d.put("contentType", contentType); - d.put("read", false); - return metadataEncoder.encode(d); - } catch (IOException e) { - LOG.info("Invalid forum post"); - return null; - } catch (GeneralSecurityException e) { - LOG.info("Invalid public key"); - return null; } - } - - private void writeAuthor(BdfWriter w, Author a) throws IOException { - w.writeListStart(); - w.writeString(a.getName()); - w.writeRaw(a.getPublicKey()); - w.writeListEnd(); + // Return the metadata + BdfDictionary meta = new BdfDictionary(); + meta.put("timestamp", timestamp); + if (parentId != null) meta.put("parent", parentId); + if (author != null) { + BdfDictionary authorMeta = new BdfDictionary(); + authorMeta.put("id", author.getId().getBytes()); + authorMeta.put("name", author.getName()); + authorMeta.put("publicKey", author.getPublicKey()); + meta.put("author", authorMeta); + } + meta.put("contentType", contentType); + meta.put("read", false); + return meta; } } diff --git a/briar-core/src/org/briarproject/messaging/MessagingModule.java b/briar-core/src/org/briarproject/messaging/MessagingModule.java index fe531f715e..4ea10f9078 100644 --- a/briar-core/src/org/briarproject/messaging/MessagingModule.java +++ b/briar-core/src/org/briarproject/messaging/MessagingModule.java @@ -3,8 +3,8 @@ package org.briarproject.messaging; import com.google.inject.AbstractModule; import com.google.inject.Provides; +import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.contact.ContactManager; -import org.briarproject.api.data.BdfReaderFactory; import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.messaging.MessagingManager; import org.briarproject.api.messaging.PrivateMessageFactory; @@ -24,10 +24,10 @@ public class MessagingModule extends AbstractModule { @Provides @Singleton PrivateMessageValidator getValidator(ValidationManager validationManager, - BdfReaderFactory bdfReaderFactory, MetadataEncoder metadataEncoder, + ClientHelper clientHelper, MetadataEncoder metadataEncoder, Clock clock) { PrivateMessageValidator validator = new PrivateMessageValidator( - bdfReaderFactory, metadataEncoder, clock); + clientHelper, metadataEncoder, clock); validationManager.registerMessageValidator(CLIENT_ID, validator); return validator; } diff --git a/briar-core/src/org/briarproject/messaging/PrivateMessageValidator.java b/briar-core/src/org/briarproject/messaging/PrivateMessageValidator.java index fa3e0ec5f3..0475da174b 100644 --- a/briar-core/src/org/briarproject/messaging/PrivateMessageValidator.java +++ b/briar-core/src/org/briarproject/messaging/PrivateMessageValidator.java @@ -2,83 +2,45 @@ package org.briarproject.messaging; import org.briarproject.api.FormatException; import org.briarproject.api.UniqueId; +import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.data.BdfDictionary; -import org.briarproject.api.data.BdfReader; -import org.briarproject.api.data.BdfReaderFactory; +import org.briarproject.api.data.BdfList; import org.briarproject.api.data.MetadataEncoder; -import org.briarproject.api.db.Metadata; import org.briarproject.api.sync.Group; -import org.briarproject.api.sync.Message; -import org.briarproject.api.sync.MessageId; -import org.briarproject.api.sync.MessageValidator; import org.briarproject.api.system.Clock; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.logging.Logger; +import org.briarproject.clients.BdfMessageValidator; import static org.briarproject.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH; import static org.briarproject.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_BODY_LENGTH; -import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; - -class PrivateMessageValidator implements MessageValidator { - - private static final Logger LOG = - Logger.getLogger(PrivateMessageValidator.class.getName()); - private final BdfReaderFactory bdfReaderFactory; - private final MetadataEncoder metadataEncoder; - private final Clock clock; +class PrivateMessageValidator extends BdfMessageValidator { - PrivateMessageValidator(BdfReaderFactory bdfReaderFactory, + PrivateMessageValidator(ClientHelper clientHelper, MetadataEncoder metadataEncoder, Clock clock) { - this.bdfReaderFactory = bdfReaderFactory; - this.metadataEncoder = metadataEncoder; - this.clock = clock; + super(clientHelper, metadataEncoder, clock); } @Override - public Metadata validateMessage(Message m, Group g) { - // Reject the message if it's too far in the future - long now = clock.currentTimeMillis(); - if (m.getTimestamp() - now > MAX_CLOCK_DIFFERENCE) { - LOG.info("Timestamp is too far in the future"); - return null; - } - try { - // Parse the message body - byte[] raw = m.getRaw(); - ByteArrayInputStream in = new ByteArrayInputStream(raw, - MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH); - BdfReader r = bdfReaderFactory.createReader(in); - MessageId parent = null; - r.readListStart(); - // Read the parent ID, if any - if (r.hasRaw()) { - byte[] id = r.readRaw(UniqueId.LENGTH); - if (id.length < UniqueId.LENGTH) throw new FormatException(); - parent = new MessageId(id); - } else { - r.readNull(); - } - // Read the content type - String contentType = r.readString(MAX_CONTENT_TYPE_LENGTH); - // Read the private message body - r.readRaw(MAX_PRIVATE_MESSAGE_BODY_LENGTH); - r.readListEnd(); - if (!r.eof()) throw new FormatException(); - // Return the metadata - BdfDictionary d = new BdfDictionary(); - d.put("timestamp", m.getTimestamp()); - if (parent != null) d.put("parent", parent.getBytes()); - d.put("contentType", contentType); - d.put("local", false); - d.put("read", false); - return metadataEncoder.encode(d); - } catch (IOException e) { - LOG.info("Invalid private message"); - return null; - } + protected BdfDictionary validateMessage(BdfList message, Group g, + long timestamp) throws FormatException { + // Parent ID, content type, private message body + checkSize(message, 3); + // Parent ID is optional + byte[] parentId = message.getOptionalRaw(0); + checkLength(parentId, UniqueId.LENGTH); + // Content type + String contentType = message.getString(1); + checkLength(contentType, 0, MAX_CONTENT_TYPE_LENGTH); + // Private message body + byte[] body = message.getRaw(2); + checkLength(body, 0, MAX_PRIVATE_MESSAGE_BODY_LENGTH); + // Return the metadata + BdfDictionary meta = new BdfDictionary(); + meta.put("timestamp", timestamp); + if (parentId != null) meta.put("parent", parentId); + meta.put("contentType", contentType); + meta.put("local", false); + meta.put("read", false); + return meta; } } diff --git a/briar-core/src/org/briarproject/properties/PropertiesModule.java b/briar-core/src/org/briarproject/properties/PropertiesModule.java index 9edbf7e16a..cd40134deb 100644 --- a/briar-core/src/org/briarproject/properties/PropertiesModule.java +++ b/briar-core/src/org/briarproject/properties/PropertiesModule.java @@ -3,8 +3,8 @@ package org.briarproject.properties; import com.google.inject.AbstractModule; import com.google.inject.Provides; +import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.contact.ContactManager; -import org.briarproject.api.data.BdfReaderFactory; import org.briarproject.api.data.MetadataEncoder; import org.briarproject.api.properties.TransportPropertyManager; import org.briarproject.api.sync.ValidationManager; @@ -21,10 +21,10 @@ public class PropertiesModule extends AbstractModule { @Provides @Singleton TransportPropertyValidator getValidator(ValidationManager validationManager, - BdfReaderFactory bdfReaderFactory, MetadataEncoder metadataEncoder, + ClientHelper clientHelper, MetadataEncoder metadataEncoder, Clock clock) { TransportPropertyValidator validator = new TransportPropertyValidator( - bdfReaderFactory, metadataEncoder, clock); + clientHelper, metadataEncoder, clock); validationManager.registerMessageValidator(CLIENT_ID, validator); return validator; } diff --git a/briar-core/src/org/briarproject/properties/TransportPropertyValidator.java b/briar-core/src/org/briarproject/properties/TransportPropertyValidator.java index 06973ae7d8..e6fcd69a6c 100644 --- a/briar-core/src/org/briarproject/properties/TransportPropertyValidator.java +++ b/briar-core/src/org/briarproject/properties/TransportPropertyValidator.java @@ -2,82 +2,52 @@ package org.briarproject.properties; import org.briarproject.api.FormatException; import org.briarproject.api.UniqueId; +import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.data.BdfDictionary; -import org.briarproject.api.data.BdfReader; -import org.briarproject.api.data.BdfReaderFactory; +import org.briarproject.api.data.BdfList; import org.briarproject.api.data.MetadataEncoder; -import org.briarproject.api.db.Metadata; import org.briarproject.api.sync.Group; -import org.briarproject.api.sync.Message; -import org.briarproject.api.sync.MessageValidator; import org.briarproject.api.system.Clock; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.logging.Logger; +import org.briarproject.clients.BdfMessageValidator; import static org.briarproject.api.TransportId.MAX_TRANSPORT_ID_LENGTH; import static org.briarproject.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT; import static org.briarproject.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH; -import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; -import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; - -class TransportPropertyValidator implements MessageValidator { - private static final Logger LOG = - Logger.getLogger(TransportPropertyValidator.class.getName()); +class TransportPropertyValidator extends BdfMessageValidator { - private final BdfReaderFactory bdfReaderFactory; - private final MetadataEncoder metadataEncoder; - private final Clock clock; - - TransportPropertyValidator(BdfReaderFactory bdfReaderFactory, + TransportPropertyValidator(ClientHelper clientHelper, MetadataEncoder metadataEncoder, Clock clock) { - this.bdfReaderFactory = bdfReaderFactory; - this.metadataEncoder = metadataEncoder; - this.clock = clock; + super(clientHelper, metadataEncoder, clock); } @Override - public Metadata validateMessage(Message m, Group g) { - // Reject the message if it's too far in the future - long now = clock.currentTimeMillis(); - if (m.getTimestamp() - now > MAX_CLOCK_DIFFERENCE) { - LOG.info("Timestamp is too far in the future"); - return null; - } - try { - // Parse the message body - byte[] raw = m.getRaw(); - ByteArrayInputStream in = new ByteArrayInputStream(raw, - MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH); - BdfReader r = bdfReaderFactory.createReader(in); - r.readListStart(); - byte[] deviceId = r.readRaw(UniqueId.LENGTH); - if (deviceId.length != UniqueId.LENGTH) throw new FormatException(); - String transportId = r.readString(MAX_TRANSPORT_ID_LENGTH); - if (transportId.length() == 0) throw new FormatException(); - long version = r.readLong(); - if (version < 0) throw new FormatException(); - r.readDictionaryStart(); - for (int i = 0; !r.hasDictionaryEnd(); i++) { - if (i == MAX_PROPERTIES_PER_TRANSPORT) - throw new FormatException(); - r.readString(MAX_PROPERTY_LENGTH); - r.readString(MAX_PROPERTY_LENGTH); - } - r.readDictionaryEnd(); - r.readListEnd(); - if (!r.eof()) throw new FormatException(); - // Return the metadata - BdfDictionary d = new BdfDictionary(); - d.put("transportId", transportId); - d.put("version", version); - d.put("local", false); - return metadataEncoder.encode(d); - } catch (IOException e) { - LOG.info("Invalid transport update"); - return null; + protected BdfDictionary validateMessage(BdfList message, Group g, + long timestamp) throws FormatException { + // Device ID, transport ID, version, properties + checkSize(message, 4); + // Device ID + byte[] deviceId = message.getRaw(0); + checkLength(deviceId, UniqueId.LENGTH); + // Transport ID + String transportId = message.getString(1); + checkLength(transportId, 1, MAX_TRANSPORT_ID_LENGTH); + // Version + long version = message.getLong(2); + if (version < 0) throw new FormatException(); + // Properties + BdfDictionary dictionary = message.getDictionary(3); + checkSize(dictionary, 0, MAX_PROPERTIES_PER_TRANSPORT); + 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 + BdfDictionary meta = new BdfDictionary(); + meta.put("transportId", transportId); + meta.put("version", version); + meta.put("local", false); + return meta; } } -- GitLab