mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 03:09:04 +01:00
Truncate all messages to valid length before sending.
This commit is contained in:
@@ -128,12 +128,7 @@ public class WriteBlogPostActivity extends BriarActivity
|
||||
}
|
||||
|
||||
private void enableOrDisablePublishButton() {
|
||||
int bodyLength =
|
||||
StringUtils.toUtf8(input.getText().toString()).length;
|
||||
if (bodyLength > 0 && bodyLength <= MAX_BLOG_POST_BODY_LENGTH)
|
||||
input.setSendButtonEnabled(true);
|
||||
else
|
||||
input.setSendButtonEnabled(false);
|
||||
input.setSendButtonEnabled(input.getText().length() > 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -142,6 +137,7 @@ public class WriteBlogPostActivity extends BriarActivity
|
||||
input.setVisibility(GONE);
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
|
||||
body = StringUtils.truncateUtf8(body, MAX_BLOG_POST_BODY_LENGTH);
|
||||
storePost(body);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.android.contact.ConversationItem.IncomingItem;
|
||||
import static org.briarproject.android.contact.ConversationItem.OutgoingItem;
|
||||
import static org.briarproject.android.fragment.SettingsFragment.SETTINGS_NAMESPACE;
|
||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_BODY_LENGTH;
|
||||
|
||||
public class ConversationActivity extends BriarActivity
|
||||
implements EventListener, IntroductionHandler, TextInputListener {
|
||||
@@ -656,6 +657,7 @@ public class ConversationActivity extends BriarActivity
|
||||
public void onSendClick(String text) {
|
||||
markMessagesRead();
|
||||
if (text.equals("")) return;
|
||||
text = StringUtils.truncateUtf8(text, MAX_PRIVATE_MESSAGE_BODY_LENGTH);
|
||||
long timestamp = System.currentTimeMillis();
|
||||
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
|
||||
createMessage(StringUtils.toUtf8(text), timestamp);
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.contact.ContactManager;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.introduction.IntroductionManager;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -33,6 +34,7 @@ import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static android.widget.Toast.LENGTH_SHORT;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH;
|
||||
|
||||
public class IntroductionMessageFragment extends BaseFragment
|
||||
implements TextInputView.TextInputListener {
|
||||
@@ -176,6 +178,7 @@ public class IntroductionMessageFragment extends BaseFragment
|
||||
ui.message.setSendButtonEnabled(false);
|
||||
|
||||
String msg = ui.message.getText().toString();
|
||||
msg = StringUtils.truncateUtf8(msg, MAX_INTRODUCTION_MESSAGE_LENGTH);
|
||||
makeIntroduction(contact1, contact2, msg);
|
||||
|
||||
// don't wait for the introduction to be made before finishing activity
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.briarproject.api.blogs.BlogSharingManager;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.forum.ForumSharingManager;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -24,6 +25,7 @@ import javax.inject.Inject;
|
||||
import static org.briarproject.android.sharing.ShareActivity.CONTACTS;
|
||||
import static org.briarproject.android.sharing.ShareActivity.getContactsFromIds;
|
||||
import static org.briarproject.api.sharing.SharingConstants.GROUP_ID;
|
||||
import static org.briarproject.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH;
|
||||
|
||||
abstract class ShareMessageFragment extends BaseFragment
|
||||
implements TextInputListener {
|
||||
@@ -103,6 +105,7 @@ abstract class ShareMessageFragment extends BaseFragment
|
||||
// disable button to prevent accidental double invitations
|
||||
ui.message.setSendButtonEnabled(false);
|
||||
|
||||
msg = StringUtils.truncateUtf8(msg, MAX_INVITATION_MESSAGE_LENGTH);
|
||||
share(msg);
|
||||
|
||||
// don't wait for the invitation to be made before finishing activity
|
||||
|
||||
@@ -13,6 +13,9 @@ public interface BlogConstants {
|
||||
/** The maximum length of a blog post's body in bytes. */
|
||||
int MAX_BLOG_POST_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
|
||||
|
||||
/** The maximum length of a blog comment in bytes. */
|
||||
int MAX_BLOG_COMMENT_LENGTH = MAX_BLOG_POST_BODY_LENGTH;
|
||||
|
||||
/** The internal name of personal blogs that are created automatically */
|
||||
String PERSONAL_BLOG_NAME = "briar.PERSONAL_BLOG_NAME";
|
||||
|
||||
|
||||
@@ -1,61 +1,7 @@
|
||||
package org.briarproject.api.blogs;
|
||||
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.sharing.InvitationItem;
|
||||
import org.briarproject.api.sharing.InvitationMessage;
|
||||
import org.briarproject.api.sharing.SharingManager;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface BlogSharingManager extends SharingManager<Blog> {
|
||||
|
||||
/**
|
||||
* Returns the unique ID of the blog sharing client.
|
||||
*/
|
||||
ClientId getClientId();
|
||||
|
||||
/**
|
||||
* Sends an invitation to share the given blog with the given contact
|
||||
* and sends an optional message along with it.
|
||||
*/
|
||||
void sendInvitation(GroupId groupId, ContactId contactId,
|
||||
String message) throws DbException;
|
||||
|
||||
/**
|
||||
* Responds to a pending blog invitation
|
||||
*/
|
||||
void respondToInvitation(Blog b, Contact c, boolean accept)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all blogs sharing messages sent by the Contact
|
||||
* identified by contactId.
|
||||
*/
|
||||
Collection<InvitationMessage> getInvitationMessages(
|
||||
ContactId contactId) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all blogs to which the user has been invited.
|
||||
*/
|
||||
Collection<InvitationItem> getInvitations() throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all contacts who are sharing the given blog with us.
|
||||
*/
|
||||
Collection<Contact> getSharedBy(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the IDs of all contacts with whom the given blog is shared.
|
||||
*/
|
||||
Collection<Contact> getSharedWith(GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the blog not already shared and no invitation is open
|
||||
*/
|
||||
boolean canBeShared(GroupId g, Contact c) throws DbException;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,51 +1,7 @@
|
||||
package org.briarproject.api.forum;
|
||||
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.sharing.InvitationItem;
|
||||
import org.briarproject.api.sharing.InvitationMessage;
|
||||
import org.briarproject.api.sharing.SharingManager;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ForumSharingManager extends SharingManager<Forum> {
|
||||
|
||||
/** Returns the unique ID of the forum sharing client. */
|
||||
ClientId getClientId();
|
||||
|
||||
/**
|
||||
* Sends an invitation to share the given forum with the given contact
|
||||
* and sends an optional message along with it.
|
||||
*/
|
||||
void sendInvitation(GroupId groupId, ContactId contactId,
|
||||
String message) throws DbException;
|
||||
|
||||
/**
|
||||
* Responds to a pending forum invitation
|
||||
*/
|
||||
void respondToInvitation(Forum f, Contact c, boolean accept)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all forum sharing messages sent by the Contact
|
||||
* identified by contactId.
|
||||
*/
|
||||
Collection<InvitationMessage> getInvitationMessages(
|
||||
ContactId contactId) throws DbException;
|
||||
|
||||
/** Returns all forums to which the user has been invited. */
|
||||
Collection<InvitationItem> getInvitations() throws DbException;
|
||||
|
||||
/** Returns all contacts who are sharing the given forum with us. */
|
||||
Collection<Contact> getSharedBy(GroupId g) throws DbException;
|
||||
|
||||
/** Returns the IDs of all contacts with whom the given forum is shared. */
|
||||
Collection<Contact> getSharedWith(GroupId g) throws DbException;
|
||||
|
||||
/** Returns true if the forum not already shared and no invitation is open */
|
||||
boolean canBeShared(GroupId g, Contact c) throws DbException;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.briarproject.api.introduction;
|
||||
|
||||
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
public interface IntroductionConstants {
|
||||
|
||||
/* Protocol roles */
|
||||
@@ -30,8 +32,18 @@ public interface IntroductionConstants {
|
||||
String SIGNATURE = "signature";
|
||||
|
||||
/* Validation Constants */
|
||||
|
||||
/**
|
||||
* The length of the message authentication code in bytes.
|
||||
*/
|
||||
int MAC_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* The maximum length of the introducer's optional message to the
|
||||
* introducees in UTF-8 bytes.
|
||||
*/
|
||||
int MAX_INTRODUCTION_MESSAGE_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024;
|
||||
|
||||
/* Introducer Local State Metadata */
|
||||
String STATE = "state";
|
||||
String ROLE = "role";
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
package org.briarproject.api.sharing;
|
||||
|
||||
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
public interface SharingConstants {
|
||||
|
||||
/** The length of a sharing session's random salt in bytes. */
|
||||
/**
|
||||
* The length of a sharing session's random salt in bytes.
|
||||
*/
|
||||
int SHARING_SALT_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* The maximum length of the optional message from the inviter to the
|
||||
* invitee in UTF-8 bytes.
|
||||
*/
|
||||
int MAX_INVITATION_MESSAGE_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1204;
|
||||
|
||||
String CONTACT_ID = "contactId";
|
||||
String GROUP_ID = "groupId";
|
||||
String TO_BE_SHARED_BY_US = "toBeSharedByUs";
|
||||
|
||||
@@ -11,15 +11,17 @@ import java.util.Collection;
|
||||
|
||||
public interface SharingManager<S extends Shareable> extends MessageTracker {
|
||||
|
||||
/** Returns the unique ID of the group sharing client. */
|
||||
/**
|
||||
* Returns the unique ID of the group sharing client.
|
||||
*/
|
||||
ClientId getClientId();
|
||||
|
||||
/**
|
||||
* Sends an invitation to share the given shareable with the given contact
|
||||
* Sends an invitation to share the given group with the given contact
|
||||
* and sends an optional message along with it.
|
||||
*/
|
||||
void sendInvitation(GroupId groupId, ContactId contactId,
|
||||
String message) throws DbException;
|
||||
String message) throws DbException;
|
||||
|
||||
/**
|
||||
* Responds to a pending group invitation
|
||||
@@ -28,22 +30,29 @@ public interface SharingManager<S extends Shareable> extends MessageTracker {
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all group sharing messages sent by the Contact
|
||||
* identified by contactId.
|
||||
* Returns all group sharing messages sent by the given contact.
|
||||
*/
|
||||
Collection<InvitationMessage> getInvitationMessages(
|
||||
ContactId contactId) throws DbException;
|
||||
|
||||
/** Returns all invitations to shareables. */
|
||||
/**
|
||||
* Returns all invitations to groups.
|
||||
*/
|
||||
Collection<InvitationItem> getInvitations() throws DbException;
|
||||
|
||||
/** Returns all contacts who are sharing the given group with us. */
|
||||
/**
|
||||
* Returns all contacts who are sharing the given group with us.
|
||||
*/
|
||||
Collection<Contact> getSharedBy(GroupId g) throws DbException;
|
||||
|
||||
/** Returns the IDs of all contacts with whom the given group is shared. */
|
||||
/**
|
||||
* Returns all contacts with whom the given group is shared.
|
||||
*/
|
||||
Collection<Contact> getSharedWith(GroupId g) throws DbException;
|
||||
|
||||
/** Returns true if the group not already shared and no invitation is open */
|
||||
/**
|
||||
* Returns true if the group not already shared and no invitation is open
|
||||
*/
|
||||
boolean canBeShared(GroupId g, Contact c) throws DbException;
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ 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.util.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -18,6 +19,7 @@ import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_COMMENT_LENGTH;
|
||||
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_BODY_LENGTH;
|
||||
import static org.briarproject.api.blogs.MessageType.COMMENT;
|
||||
import static org.briarproject.api.blogs.MessageType.POST;
|
||||
@@ -42,7 +44,8 @@ class BlogPostFactoryImpl implements BlogPostFactory {
|
||||
throws FormatException, GeneralSecurityException {
|
||||
|
||||
// Validate the arguments
|
||||
if (body.length() > MAX_BLOG_POST_BODY_LENGTH)
|
||||
int bodyLength = StringUtils.toUtf8(body).length;
|
||||
if (bodyLength > MAX_BLOG_POST_BODY_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
// Serialise the data to be signed
|
||||
@@ -62,6 +65,13 @@ class BlogPostFactoryImpl implements BlogPostFactory {
|
||||
@Nullable String comment, MessageId pOriginalId, MessageId parentId)
|
||||
throws FormatException, GeneralSecurityException {
|
||||
|
||||
if (comment != null) {
|
||||
int commentLength = StringUtils.toUtf8(comment).length;
|
||||
if (commentLength == 0) throw new IllegalArgumentException();
|
||||
if (commentLength > MAX_BLOG_COMMENT_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
long timestamp = clock.currentTimeMillis();
|
||||
|
||||
// Generate the signature
|
||||
|
||||
@@ -40,6 +40,7 @@ import static org.briarproject.api.blogs.BlogConstants.KEY_READ;
|
||||
import static org.briarproject.api.blogs.BlogConstants.KEY_TIMESTAMP;
|
||||
import static org.briarproject.api.blogs.BlogConstants.KEY_TIME_RECEIVED;
|
||||
import static org.briarproject.api.blogs.BlogConstants.KEY_TYPE;
|
||||
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_COMMENT_LENGTH;
|
||||
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_BODY_LENGTH;
|
||||
import static org.briarproject.api.blogs.MessageType.COMMENT;
|
||||
import static org.briarproject.api.blogs.MessageType.POST;
|
||||
@@ -125,7 +126,7 @@ class BlogPostValidator extends BdfMessageValidator {
|
||||
|
||||
// Comment
|
||||
String comment = body.getOptionalString(0);
|
||||
checkLength(comment, 1, MAX_BLOG_POST_BODY_LENGTH);
|
||||
checkLength(comment, 1, MAX_BLOG_COMMENT_LENGTH);
|
||||
|
||||
// parent_original_id
|
||||
// The ID of a post or comment in this group or another group
|
||||
@@ -216,7 +217,7 @@ class BlogPostValidator extends BdfMessageValidator {
|
||||
|
||||
// Body of Wrapped Comment
|
||||
String comment = body.getOptionalString(2);
|
||||
checkLength(comment, 1, MAX_BLOG_POST_BODY_LENGTH);
|
||||
checkLength(comment, 1, MAX_BLOG_COMMENT_LENGTH);
|
||||
|
||||
// c_parent_original_id
|
||||
// Taken from the original comment
|
||||
|
||||
@@ -484,10 +484,7 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
|
||||
|
||||
private String getPostBody(String text) {
|
||||
text = clean(text, article);
|
||||
byte[] textBytes = StringUtils.toUtf8(text);
|
||||
if (textBytes.length <= MAX_BLOG_POST_BODY_LENGTH)
|
||||
return text;
|
||||
return StringUtils.fromUtf8(textBytes, 0, MAX_BLOG_POST_BODY_LENGTH);
|
||||
return StringUtils.truncateUtf8(text, MAX_BLOG_POST_BODY_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,6 +31,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.CONTACT_ID
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.CONTACT_ID_2;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID_1;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID_2;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_TIME;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MSG;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.PUBLIC_KEY1;
|
||||
@@ -103,7 +104,7 @@ class IntroducerManager {
|
||||
return d;
|
||||
}
|
||||
|
||||
public void makeIntroduction(Transaction txn, Contact c1, Contact c2,
|
||||
void makeIntroduction(Transaction txn, Contact c1, Contact c2,
|
||||
String msg, long timestamp) throws DbException, FormatException {
|
||||
|
||||
// TODO check for existing session with those contacts?
|
||||
@@ -116,6 +117,9 @@ class IntroducerManager {
|
||||
BdfDictionary localAction = new BdfDictionary();
|
||||
localAction.put(TYPE, TYPE_REQUEST);
|
||||
if (!StringUtils.isNullOrEmpty(msg)) {
|
||||
int msgLength = StringUtils.toUtf8(msg).length;
|
||||
if (msgLength > MAX_INTRODUCTION_MESSAGE_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
localAction.put(MSG, msg);
|
||||
}
|
||||
localAction.put(PUBLIC_KEY1, c1.getAuthor().getPublicKey());
|
||||
|
||||
@@ -21,6 +21,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.E_PUBLIC_K
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MAC;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MAC_LENGTH;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_ID;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MESSAGE_TIME;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MSG;
|
||||
@@ -37,7 +38,6 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUE
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE;
|
||||
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.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
class IntroductionValidator extends BdfMessageValidator {
|
||||
|
||||
@@ -92,7 +92,7 @@ class IntroductionValidator extends BdfMessageValidator {
|
||||
String msg = null;
|
||||
if (message.size() == 5) {
|
||||
msg = message.getString(4);
|
||||
checkLength(msg, 0, MAX_MESSAGE_BODY_LENGTH);
|
||||
checkLength(msg, 0, MAX_INTRODUCTION_MESSAGE_LENGTH);
|
||||
}
|
||||
|
||||
// Return the metadata
|
||||
|
||||
@@ -204,6 +204,7 @@ class BlogSharingManagerImpl extends
|
||||
.createBlog(msg.getBlogTitle(), msg.getBlogDesc(), author);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Blog parse(BlogInviteeSessionState state) {
|
||||
Author author = authorFactory
|
||||
.createAuthor(state.getBlogAuthorName(),
|
||||
|
||||
@@ -16,14 +16,15 @@ import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME;
|
||||
import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC;
|
||||
import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
|
||||
import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY;
|
||||
import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE;
|
||||
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_DESC_LENGTH;
|
||||
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_TITLE_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.sharing.SharingConstants.INVITATION_MSG;
|
||||
import static org.briarproject.api.sharing.SharingConstants.LOCAL;
|
||||
import static org.briarproject.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH;
|
||||
import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
|
||||
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT;
|
||||
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT;
|
||||
@@ -32,7 +33,6 @@ import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVIT
|
||||
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE;
|
||||
import static org.briarproject.api.sharing.SharingConstants.TIME;
|
||||
import static org.briarproject.api.sharing.SharingConstants.TYPE;
|
||||
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
class BlogSharingValidator extends BdfMessageValidator {
|
||||
|
||||
@@ -76,7 +76,7 @@ class BlogSharingValidator extends BdfMessageValidator {
|
||||
|
||||
if (body.size() > 5) {
|
||||
String msg = body.getString(5);
|
||||
checkLength(msg, 0, MAX_MESSAGE_BODY_LENGTH);
|
||||
checkLength(msg, 0, MAX_INVITATION_MESSAGE_LENGTH);
|
||||
d.put(INVITATION_MSG, msg);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -167,6 +167,7 @@ class ForumSharingManagerImpl extends
|
||||
.createForum(msg.getForumName(), msg.getForumSalt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Forum parse(ForumInviteeSessionState state) {
|
||||
return forumFactory
|
||||
.createForum(state.getForumName(), state.getForumSalt());
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.briarproject.sharing;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.clients.BdfMessageContext;
|
||||
import org.briarproject.api.clients.ClientHelper;
|
||||
import org.briarproject.api.clients.SessionId;
|
||||
import org.briarproject.api.clients.BdfMessageContext;
|
||||
import org.briarproject.api.data.BdfDictionary;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.data.MetadataEncoder;
|
||||
@@ -20,6 +20,7 @@ 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.sharing.SharingConstants.INVITATION_MSG;
|
||||
import static org.briarproject.api.sharing.SharingConstants.LOCAL;
|
||||
import static org.briarproject.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH;
|
||||
import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
|
||||
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT;
|
||||
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT;
|
||||
@@ -28,7 +29,6 @@ import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVIT
|
||||
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE;
|
||||
import static org.briarproject.api.sharing.SharingConstants.TIME;
|
||||
import static org.briarproject.api.sharing.SharingConstants.TYPE;
|
||||
import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||
|
||||
class ForumSharingValidator extends BdfMessageValidator {
|
||||
|
||||
@@ -61,7 +61,7 @@ class ForumSharingValidator extends BdfMessageValidator {
|
||||
|
||||
if (body.size() > 4) {
|
||||
String msg = body.getString(4);
|
||||
checkLength(msg, 0, MAX_MESSAGE_BODY_LENGTH);
|
||||
checkLength(msg, 0, MAX_INVITATION_MESSAGE_LENGTH);
|
||||
d.put(INVITATION_MSG, msg);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.briarproject.api.sharing.InvitationItem;
|
||||
import org.briarproject.api.sharing.InvitationMessage;
|
||||
import org.briarproject.api.sharing.Shareable;
|
||||
import org.briarproject.api.sharing.SharingManager;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.Group;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.Message;
|
||||
@@ -58,6 +57,7 @@ import static org.briarproject.api.clients.ProtocolEngine.StateUpdate;
|
||||
import static org.briarproject.api.sharing.SharingConstants.CONTACT_ID;
|
||||
import static org.briarproject.api.sharing.SharingConstants.IS_SHARER;
|
||||
import static org.briarproject.api.sharing.SharingConstants.LOCAL;
|
||||
import static org.briarproject.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH;
|
||||
import static org.briarproject.api.sharing.SharingConstants.SESSION_ID;
|
||||
import static org.briarproject.api.sharing.SharingConstants.SHAREABLE_ID;
|
||||
import static org.briarproject.api.sharing.SharingConstants.SHARED_BY_US;
|
||||
@@ -115,8 +115,6 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
|
||||
localGroup = contactGroupFactory.createLocalGroup(getClientId());
|
||||
}
|
||||
|
||||
public abstract ClientId getClientId();
|
||||
|
||||
protected abstract InvitationMessage createInvitationRequest(MessageId id,
|
||||
I msg, ContactId contactId, boolean available, long time,
|
||||
boolean local, boolean sent, boolean seen, boolean read);
|
||||
@@ -282,6 +280,9 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS
|
||||
|
||||
// add invitation message to local state to be available for engine
|
||||
if (!StringUtils.isNullOrEmpty(msg)) {
|
||||
int msgLength = StringUtils.toUtf8(msg).length;
|
||||
if (msgLength > MAX_INVITATION_MESSAGE_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
localState.setMessage(msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
package org.briarproject.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.util.Collection;
|
||||
|
||||
import static java.nio.charset.CodingErrorAction.IGNORE;
|
||||
|
||||
public class StringUtils {
|
||||
|
||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
|
||||
private static final char[] HEX = new char[] {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
@@ -32,23 +40,29 @@ public class StringUtils {
|
||||
}
|
||||
|
||||
public static String fromUtf8(byte[] bytes) {
|
||||
try {
|
||||
return new String(bytes, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return fromUtf8(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
public static String fromUtf8(byte[] bytes, int off, int len) {
|
||||
CharsetDecoder decoder = UTF_8.newDecoder();
|
||||
decoder.onMalformedInput(IGNORE);
|
||||
decoder.onUnmappableCharacter(IGNORE);
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes, off, len);
|
||||
try {
|
||||
return new String(bytes, off, len, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return decoder.decode(buffer).toString();
|
||||
} catch (CharacterCodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String truncateUtf8(String s, int maxUtf8Length) {
|
||||
byte[] utf8 = toUtf8(s);
|
||||
if (utf8.length <= maxUtf8Length) return s;
|
||||
return fromUtf8(utf8, 0, maxUtf8Length);
|
||||
}
|
||||
|
||||
/** Converts the given byte array to a hex character array. */
|
||||
public static char[] toHexChars(byte[] bytes) {
|
||||
private static char[] toHexChars(byte[] bytes) {
|
||||
char[] hex = new char[bytes.length * 2];
|
||||
for (int i = 0, j = 0; i < bytes.length; i++) {
|
||||
hex[j++] = HEX[(bytes[i] >> 4) & 0xF];
|
||||
|
||||
@@ -30,6 +30,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.E_PUBLIC_K
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.GROUP_ID;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MAC;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MAC_LENGTH;
|
||||
import static org.briarproject.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH;
|
||||
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;
|
||||
@@ -83,8 +84,10 @@ public class IntroductionValidatorTest extends BriarTestCase {
|
||||
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);
|
||||
final byte[] publicKey =
|
||||
TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH);
|
||||
final String text =
|
||||
TestUtils.getRandomString(MAX_INTRODUCTION_MESSAGE_LENGTH);
|
||||
|
||||
BdfList body = BdfList.of(TYPE_REQUEST, sessionId,
|
||||
name, publicKey, text);
|
||||
@@ -107,14 +110,15 @@ public class IntroductionValidatorTest extends BriarTestCase {
|
||||
|
||||
// no NAME is message
|
||||
BdfList body = BdfList.of(msg.getLong(TYPE), msg.getRaw(SESSION_ID),
|
||||
msg.getRaw(PUBLIC_KEY));
|
||||
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 {
|
||||
public void testValidateIntroductionRequestWithLongName()
|
||||
throws IOException {
|
||||
// too long NAME in message
|
||||
BdfDictionary msg = getValidIntroductionRequest();
|
||||
msg.put(NAME, msg.get(NAME) + "x");
|
||||
@@ -315,7 +319,8 @@ public class IntroductionValidatorTest extends BriarTestCase {
|
||||
}
|
||||
|
||||
@Test(expected = FormatException.class)
|
||||
public void testValidateIntroductionAckWithLongSessionId() throws IOException {
|
||||
public void testValidateIntroductionAckWithLongSessionId()
|
||||
throws IOException {
|
||||
BdfDictionary msg = BdfDictionary.of(
|
||||
new BdfEntry(TYPE, TYPE_ACK),
|
||||
new BdfEntry(SESSION_ID, new byte[SessionId.LENGTH + 1])
|
||||
|
||||
@@ -5,30 +5,172 @@ import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
public class StringUtilsTest extends BriarTestCase {
|
||||
|
||||
@Test
|
||||
public void testToHexString() {
|
||||
byte[] b = new byte[] {1, 2, 3, 127, -128};
|
||||
String s = StringUtils.toHexString(b);
|
||||
assertEquals("0102037F80", s);
|
||||
byte[] b = new byte[] {
|
||||
0x00, 0x01, 0x02, 0x03, 0x7F, (byte) 0x80,
|
||||
0x0A, 0x0B, 0x0C, 0x0D, 0x0E, (byte) 0xFF
|
||||
};
|
||||
String expected = "000102037F800A0B0C0D0EFF";
|
||||
assertEquals(expected, StringUtils.toHexString(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromHexString() {
|
||||
try {
|
||||
StringUtils.fromHexString("12345");
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {}
|
||||
try {
|
||||
StringUtils.fromHexString("ABCDEFGH");
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {}
|
||||
byte[] b = StringUtils.fromHexString("0102037F80");
|
||||
assertArrayEquals(new byte[] {1, 2, 3, 127, -128}, b);
|
||||
b = StringUtils.fromHexString("0a0b0c0d0e0f");
|
||||
assertArrayEquals(new byte[] {10, 11, 12, 13, 14, 15}, b);
|
||||
public void testToHexStringEmptyInput() {
|
||||
assertEquals("", StringUtils.toHexString(new byte[0]));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testFromHexStringRejectsInvalidLength() {
|
||||
StringUtils.fromHexString("12345");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testFromHexStringRejectsInvalidCharacter() {
|
||||
StringUtils.fromHexString("ABCDEFGH");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromHexStringUppercase() {
|
||||
String s = "000102037F800A0B0C0D0EFF";
|
||||
byte[] expected = new byte[] {
|
||||
0x00, 0x01, 0x02, 0x03, 0x7F, (byte) 0x80,
|
||||
0x0A, 0x0B, 0x0C, 0x0D, 0x0E, (byte) 0xFF
|
||||
};
|
||||
assertArrayEquals(expected, StringUtils.fromHexString(s));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromHexStringLowercase() {
|
||||
String s = "000102037f800a0b0c0d0eff";
|
||||
byte[] expected = new byte[] {
|
||||
0x00, 0x01, 0x02, 0x03, 0x7F, (byte) 0x80,
|
||||
0x0A, 0x0B, 0x0C, 0x0D, 0x0E, (byte) 0xFF
|
||||
};
|
||||
assertArrayEquals(expected, StringUtils.fromHexString(s));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromHexStringEmptyInput() {
|
||||
assertArrayEquals(new byte[0], StringUtils.fromHexString(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToUtf8EncodesNullCharacterAsStandardUtf8() {
|
||||
// The Unicode null character should be encoded as a single null byte,
|
||||
// not as two bytes as in CESU-8 and modified UTF-8
|
||||
String s = "\u0000";
|
||||
assertArrayEquals(new byte[1], StringUtils.toUtf8(s));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToUtf8EncodesSupplementaryCharactersAsStandardUtf8() {
|
||||
// A supplementary character should be encoded as four bytes, not as a
|
||||
// surrogate pair as in CESU-8 and modified UTF-8
|
||||
String s = "\u0045\u0205\uD801\uDC00";
|
||||
byte[] expected = new byte[] {
|
||||
0x45, // U+0045
|
||||
(byte) 0xC8, (byte) 0x85, // U+0205
|
||||
(byte) 0xF0, (byte) 0x90, (byte) 0x90, (byte) 0x80 // U+10400
|
||||
};
|
||||
assertArrayEquals(expected, StringUtils.toUtf8(s));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToUtf8EmptyInput() {
|
||||
assertArrayEquals(new byte[0], StringUtils.toUtf8(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromUtf8AcceptsNullCharacterUsingStandardUtf8() {
|
||||
// The UTF-8 encoding of the null character is valid
|
||||
assertEquals("\u0000", StringUtils.fromUtf8(new byte[1]));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromUtf8RemovesNullCharacterUsingModifiedUtf8() {
|
||||
// The modified UTF-8 encoding of the null character is not valid
|
||||
byte[] b = new byte[] {
|
||||
(byte) 0xC0, (byte) 0x80, // Null character as modified UTF-8
|
||||
(byte) 0xC8, (byte) 0x85 // U+0205
|
||||
};
|
||||
// Conversion should ignore the invalid character and return the rest
|
||||
String expected = "\u0205";
|
||||
assertEquals(expected, StringUtils.fromUtf8(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromUtf8AcceptsSupplementaryCharacterUsingStandardUtf8() {
|
||||
// The UTF-8 encoding of a supplementary character is valid and should
|
||||
// be converted to a surrogate pair
|
||||
byte[] b = new byte[] {
|
||||
(byte) 0xF0, (byte) 0x90, (byte) 0x90, (byte) 0x80, // U+10400
|
||||
(byte) 0xC8, (byte) 0x85 // U+0205
|
||||
};
|
||||
String expected = "\uD801\uDC00\u0205"; // Surrogate pair
|
||||
assertEquals(expected, StringUtils.fromUtf8(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromUtf8RemovesSupplementaryCharacterUsingModifiedUtf8() {
|
||||
// The CESU-8 or modified UTF-8 encoding of a supplementary character
|
||||
// is not valid
|
||||
byte[] b = new byte[] {
|
||||
(byte) 0xED, (byte) 0xA0, (byte) 0x81, // U+10400 as CSEU-8
|
||||
(byte) 0xED, (byte) 0xB0, (byte) 0x80,
|
||||
(byte) 0xC8, (byte) 0x85 // U+0205
|
||||
};
|
||||
// Converstion should ignore the invalid character and return the rest
|
||||
String expected = "\u0205";
|
||||
assertEquals(expected, StringUtils.fromUtf8(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFromUtf8EmptyInput() {
|
||||
assertEquals("", StringUtils.fromUtf8(new byte[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateUtf8ReturnsArgumentIfNotTruncated() {
|
||||
String s = "Hello";
|
||||
assertSame(s, StringUtils.truncateUtf8(s, 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateUtf8ChecksUtf8LengthNotStringLength() {
|
||||
String s = "H\u0205llo";
|
||||
assertEquals(5, s.length());
|
||||
assertEquals(6, StringUtils.toUtf8(s).length);
|
||||
String expected = "H\u0205ll"; // Sixth byte removed
|
||||
assertEquals(expected, StringUtils.truncateUtf8(s, 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateUtf8RemovesTruncatedCharacter() {
|
||||
String s = "\u0205\u0205"; // String requires four bytes
|
||||
String expected = "\u0205"; // Partial character removed
|
||||
String truncated = StringUtils.truncateUtf8(s, 3);
|
||||
assertEquals(expected, truncated);
|
||||
// Converting the truncated string should not exceed the max length
|
||||
assertEquals(2, StringUtils.toUtf8(truncated).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateUtf8RemovesTruncatedSurrogatePair() {
|
||||
String s = "\u0205\uD801\uDC00"; // String requires six bytes
|
||||
String expected = "\u0205"; // Partial character removed
|
||||
String truncated = StringUtils.truncateUtf8(s, 3);
|
||||
assertEquals(expected, truncated);
|
||||
// Converting the truncated string should not exceed the max length
|
||||
assertEquals(2, StringUtils.toUtf8(truncated).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTruncateUtf8EmptyInput() {
|
||||
assertEquals("", StringUtils.truncateUtf8("", 123));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user