From 186ac30f376cb5be9425dc39aed8aa3b2ee9327e Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 19 Nov 2020 15:09:58 -0300 Subject: [PATCH 01/57] Use metadata constants in TransportPropertyValidator --- .../bramble/properties/TransportPropertyValidator.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyValidator.java b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyValidator.java index eace2fed7..e74ca3f69 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyValidator.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyValidator.java @@ -15,6 +15,9 @@ import org.briarproject.bramble.api.system.Clock; import javax.annotation.concurrent.Immutable; import static org.briarproject.bramble.api.plugin.TransportId.MAX_TRANSPORT_ID_LENGTH; +import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_LOCAL; +import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_TRANSPORT_ID; +import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_VERSION; import static org.briarproject.bramble.util.ValidationUtils.checkLength; import static org.briarproject.bramble.util.ValidationUtils.checkSize; @@ -43,9 +46,9 @@ class TransportPropertyValidator extends BdfMessageValidator { clientHelper.parseAndValidateTransportProperties(dictionary); // Return the metadata BdfDictionary meta = new BdfDictionary(); - meta.put("transportId", transportId); - meta.put("version", version); - meta.put("local", false); + meta.put(MSG_KEY_TRANSPORT_ID, transportId); + meta.put(MSG_KEY_VERSION, version); + meta.put(MSG_KEY_LOCAL, false); return new BdfMessageContext(meta); } } From ef9b22670df074b1fcd6a6cde9d582a4e2ce1cd8 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 19 Nov 2020 17:42:56 -0300 Subject: [PATCH 02/57] Factor our attachment classes and constants because they will be used by more than one client --- .../AttachmentRetrieverIntegrationTest.java | 4 ++-- .../attachment/AttachmentCreationTask.java | 2 +- .../android/attachment/AttachmentCreator.java | 2 +- .../attachment/AttachmentCreatorImpl.java | 6 +++--- .../briar/android/attachment/AttachmentItem.java | 2 +- .../android/attachment/AttachmentManager.java | 2 +- .../android/attachment/AttachmentRetriever.java | 4 ++-- .../attachment/AttachmentRetrieverImpl.java | 4 ++-- .../briar/android/blog/ReblogFragment.java | 2 +- .../android/blog/WriteBlogPostActivity.java | 2 +- .../conversation/ConversationActivity.java | 2 +- .../conversation/ConversationViewModel.java | 2 +- .../android/conversation/ImageViewModel.java | 2 +- .../conversation/glide/BriarDataFetcher.java | 2 +- .../IntroductionMessageFragment.java | 2 +- .../android/sharing/BaseMessageFragment.java | 2 +- .../android/threaded/ThreadListActivity.java | 2 +- .../briar/android/view/TextSendController.java | 2 +- .../attachment/AttachmentRetrieverTest.java | 4 ++-- .../api/{messaging => media}/Attachment.java | 2 +- .../{messaging => media}/AttachmentHeader.java | 2 +- .../FileTooBigException.java | 2 +- .../InvalidAttachmentException.java | 2 +- .../briar/api/messaging/MessagingManager.java | 4 ++++ .../briar/api/messaging/PrivateMessage.java | 1 + .../api/messaging/PrivateMessageFactory.java | 1 + .../api/messaging/PrivateMessageHeader.java | 1 + .../CountingInputStream.java | 8 ++++---- .../briarproject/briar/media/MediaConstants.java | 8 ++++++++ .../briar/messaging/MessagingConstants.java | 2 -- .../briar/messaging/MessagingManagerImpl.java | 16 ++++++++-------- .../messaging/PrivateMessageFactoryImpl.java | 2 +- .../briar/messaging/PrivateMessageValidator.java | 5 +++-- .../CountingInputStreamTest.java | 2 +- .../messaging/MessageSizeIntegrationTest.java | 2 +- .../MessagingManagerIntegrationTest.java | 2 +- .../messaging/PrivateMessageValidatorTest.java | 4 ++-- .../SimplexMessagingIntegrationTest.java | 2 +- 38 files changed, 66 insertions(+), 52 deletions(-) rename briar-api/src/main/java/org/briarproject/briar/api/{messaging => media}/Attachment.java (91%) rename briar-api/src/main/java/org/briarproject/briar/api/{messaging => media}/AttachmentHeader.java (94%) rename briar-api/src/main/java/org/briarproject/briar/api/{messaging => media}/FileTooBigException.java (65%) rename briar-api/src/main/java/org/briarproject/briar/api/{messaging => media}/InvalidAttachmentException.java (90%) rename briar-core/src/main/java/org/briarproject/briar/{messaging => media}/CountingInputStream.java (86%) create mode 100644 briar-core/src/main/java/org/briarproject/briar/media/MediaConstants.java rename briar-core/src/test/java/org/briarproject/briar/{messaging => media}/CountingInputStreamTest.java (99%) diff --git a/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/attachment/AttachmentRetrieverIntegrationTest.java b/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/attachment/AttachmentRetrieverIntegrationTest.java index 866aecec4..ad296476f 100644 --- a/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/attachment/AttachmentRetrieverIntegrationTest.java +++ b/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/attachment/AttachmentRetrieverIntegrationTest.java @@ -2,8 +2,8 @@ package org.briarproject.briar.android.attachment; import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.messaging.Attachment; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.Attachment; +import org.briarproject.briar.api.media.AttachmentHeader; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreationTask.java b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreationTask.java index 10a793b86..58e2fb1ea 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreationTask.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreationTask.java @@ -9,7 +9,7 @@ import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import org.briarproject.briar.api.messaging.MessagingManager; import org.jsoup.UnsupportedMimeTypeException; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreator.java b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreator.java index c8d9d617e..588c80f30 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreator.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreator.java @@ -6,7 +6,7 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import java.util.Collection; import java.util.List; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreatorImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreatorImpl.java index 4eb79a02f..650801c77 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreatorImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreatorImpl.java @@ -10,9 +10,9 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.R; -import org.briarproject.briar.api.messaging.Attachment; -import org.briarproject.briar.api.messaging.AttachmentHeader; -import org.briarproject.briar.api.messaging.FileTooBigException; +import org.briarproject.briar.api.media.Attachment; +import org.briarproject.briar.api.media.AttachmentHeader; +import org.briarproject.briar.api.media.FileTooBigException; import org.briarproject.briar.api.messaging.MessagingManager; import org.jsoup.UnsupportedMimeTypeException; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentItem.java b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentItem.java index 9ce231c7d..f24f507f4 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentItem.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentItem.java @@ -5,7 +5,7 @@ import android.os.Parcelable; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import javax.annotation.concurrent.Immutable; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentManager.java b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentManager.java index db7f0e850..3c824a161 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentManager.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentManager.java @@ -3,7 +3,7 @@ package org.briarproject.briar.android.attachment; import android.net.Uri; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import java.util.Collection; import java.util.List; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentRetriever.java b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentRetriever.java index 2bf6b69ea..68b8a5b37 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentRetriever.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentRetriever.java @@ -4,8 +4,8 @@ import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.messaging.Attachment; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.Attachment; +import org.briarproject.briar.api.media.AttachmentHeader; import org.briarproject.briar.api.messaging.PrivateMessageHeader; import org.briarproject.briar.api.messaging.event.AttachmentReceivedEvent; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentRetrieverImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentRetrieverImpl.java index 1faa7dd1e..8ac9666f6 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentRetrieverImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentRetrieverImpl.java @@ -6,8 +6,8 @@ import org.briarproject.bramble.api.db.NoSuchMessageException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.android.attachment.AttachmentItem.State; -import org.briarproject.briar.api.messaging.Attachment; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.Attachment; +import org.briarproject.briar.api.media.AttachmentHeader; import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.PrivateMessageHeader; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/ReblogFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/ReblogFragment.java index 3f6f881ad..98cb51794 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/ReblogFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/ReblogFragment.java @@ -20,7 +20,7 @@ import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.view.TextInputView; import org.briarproject.briar.android.view.TextSendController; import org.briarproject.briar.android.view.TextSendController.SendListener; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import java.util.List; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/blog/WriteBlogPostActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/blog/WriteBlogPostActivity.java index 6ac261ecf..eaf047fe9 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/blog/WriteBlogPostActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/blog/WriteBlogPostActivity.java @@ -22,7 +22,7 @@ import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.blog.BlogPost; import org.briarproject.briar.api.blog.BlogPostFactory; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import java.security.GeneralSecurityException; import java.util.List; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java index 9f85d0d8f..481aa7683 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationActivity.java @@ -71,7 +71,7 @@ import org.briarproject.briar.api.conversation.DeletionResult; import org.briarproject.briar.api.conversation.event.ConversationMessageReceivedEvent; import org.briarproject.briar.api.forum.ForumSharingManager; import org.briarproject.briar.api.introduction.IntroductionManager; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.PrivateMessageHeader; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java index 7ff5d50e4..abcc55a40 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java @@ -31,7 +31,7 @@ import org.briarproject.briar.android.util.UiUtils; import org.briarproject.briar.android.viewmodel.DbViewModel; import org.briarproject.briar.android.viewmodel.LiveEvent; import org.briarproject.briar.android.viewmodel.MutableLiveEvent; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.PrivateMessage; import org.briarproject.briar.api.messaging.PrivateMessageFactory; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageViewModel.java index eeba81f3b..3f3feba1a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageViewModel.java @@ -20,7 +20,7 @@ import org.briarproject.briar.android.attachment.AttachmentItem; import org.briarproject.briar.android.viewmodel.DbViewModel; import org.briarproject.briar.android.viewmodel.LiveEvent; import org.briarproject.briar.android.viewmodel.MutableLiveEvent; -import org.briarproject.briar.api.messaging.Attachment; +import org.briarproject.briar.api.media.Attachment; import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.event.AttachmentReceivedEvent; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/glide/BriarDataFetcher.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/glide/BriarDataFetcher.java index d208ab475..dff40633e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/glide/BriarDataFetcher.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/glide/BriarDataFetcher.java @@ -8,7 +8,7 @@ import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.android.attachment.AttachmentItem; -import org.briarproject.briar.api.messaging.Attachment; +import org.briarproject.briar.api.media.Attachment; import org.briarproject.briar.api.messaging.MessagingManager; import java.io.InputStream; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java index e7d85dc91..6321dde14 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/introduction/IntroductionMessageFragment.java @@ -23,7 +23,7 @@ import org.briarproject.briar.android.view.TextInputView; import org.briarproject.briar.android.view.TextSendController; import org.briarproject.briar.android.view.TextSendController.SendListener; import org.briarproject.briar.api.introduction.IntroductionManager; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import java.util.List; import java.util.logging.Logger; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/sharing/BaseMessageFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/sharing/BaseMessageFragment.java index 1d33fd83e..f6592f778 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/sharing/BaseMessageFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/sharing/BaseMessageFragment.java @@ -15,7 +15,7 @@ import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.view.LargeTextInputView; import org.briarproject.briar.android.view.TextSendController; import org.briarproject.briar.android.view.TextSendController.SendListener; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import java.util.List; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java index 22138f19e..487d39a48 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/threaded/ThreadListActivity.java @@ -28,7 +28,7 @@ import org.briarproject.briar.android.view.TextSendController; import org.briarproject.briar.android.view.TextSendController.SendListener; import org.briarproject.briar.android.view.UnreadMessageButton; import org.briarproject.briar.api.client.NamedGroup; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import java.util.Collection; import java.util.List; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java b/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java index ae2ac2313..573c342ec 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/view/TextSendController.java @@ -8,7 +8,7 @@ import com.google.android.material.snackbar.Snackbar; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.R; import org.briarproject.briar.android.view.EmojiTextInputView.TextInputListener; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import java.util.List; diff --git a/briar-android/src/test/java/org/briarproject/briar/android/attachment/AttachmentRetrieverTest.java b/briar-android/src/test/java/org/briarproject/briar/android/attachment/AttachmentRetrieverTest.java index 5504da00b..7894acc67 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/attachment/AttachmentRetrieverTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/attachment/AttachmentRetrieverTest.java @@ -3,8 +3,8 @@ package org.briarproject.briar.android.attachment; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.ImmediateExecutor; -import org.briarproject.briar.api.messaging.Attachment; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.Attachment; +import org.briarproject.briar.api.media.AttachmentHeader; import org.briarproject.briar.api.messaging.MessagingManager; import org.jmock.Expectations; import org.jmock.lib.legacy.ClassImposteriser; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/Attachment.java b/briar-api/src/main/java/org/briarproject/briar/api/media/Attachment.java similarity index 91% rename from briar-api/src/main/java/org/briarproject/briar/api/messaging/Attachment.java rename to briar-api/src/main/java/org/briarproject/briar/api/media/Attachment.java index 61bb0b0eb..9fb533c77 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/Attachment.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/media/Attachment.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.api.messaging; +package org.briarproject.briar.api.media; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/AttachmentHeader.java b/briar-api/src/main/java/org/briarproject/briar/api/media/AttachmentHeader.java similarity index 94% rename from briar-api/src/main/java/org/briarproject/briar/api/messaging/AttachmentHeader.java rename to briar-api/src/main/java/org/briarproject/briar/api/media/AttachmentHeader.java index 970401211..1cd99895a 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/AttachmentHeader.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/media/AttachmentHeader.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.api.messaging; +package org.briarproject.briar.api.media; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/FileTooBigException.java b/briar-api/src/main/java/org/briarproject/briar/api/media/FileTooBigException.java similarity index 65% rename from briar-api/src/main/java/org/briarproject/briar/api/messaging/FileTooBigException.java rename to briar-api/src/main/java/org/briarproject/briar/api/media/FileTooBigException.java index f7d9c7c04..b41c1d8b8 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/FileTooBigException.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/media/FileTooBigException.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.api.messaging; +package org.briarproject.briar.api.media; import java.io.IOException; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/InvalidAttachmentException.java b/briar-api/src/main/java/org/briarproject/briar/api/media/InvalidAttachmentException.java similarity index 90% rename from briar-api/src/main/java/org/briarproject/briar/api/messaging/InvalidAttachmentException.java rename to briar-api/src/main/java/org/briarproject/briar/api/media/InvalidAttachmentException.java index df32602d1..8c8dea650 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/InvalidAttachmentException.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/media/InvalidAttachmentException.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.api.messaging; +package org.briarproject.briar.api.media; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java index ccb8f776f..1e255874d 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/MessagingManager.java @@ -8,6 +8,10 @@ import org.briarproject.bramble.api.sync.ClientId; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.api.conversation.ConversationManager.ConversationClient; +import org.briarproject.briar.api.media.Attachment; +import org.briarproject.briar.api.media.AttachmentHeader; +import org.briarproject.briar.api.media.FileTooBigException; +import org.briarproject.briar.api.media.InvalidAttachmentException; import java.io.IOException; import java.io.InputStream; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java index 58bde1576..586180a93 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessage.java @@ -2,6 +2,7 @@ package org.briarproject.briar.api.messaging; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.Message; +import org.briarproject.briar.api.media.AttachmentHeader; import java.util.List; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFactory.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFactory.java index 2f7e1127b..7adb75fbe 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFactory.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageFactory.java @@ -3,6 +3,7 @@ package org.briarproject.briar.api.messaging; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.briar.api.media.AttachmentHeader; import java.util.List; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java index 010466f6f..a4673c535 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/messaging/PrivateMessageHeader.java @@ -5,6 +5,7 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.api.conversation.ConversationMessageHeader; import org.briarproject.briar.api.conversation.ConversationMessageVisitor; +import org.briarproject.briar.api.media.AttachmentHeader; import java.util.List; diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/CountingInputStream.java b/briar-core/src/main/java/org/briarproject/briar/media/CountingInputStream.java similarity index 86% rename from briar-core/src/main/java/org/briarproject/briar/messaging/CountingInputStream.java rename to briar-core/src/main/java/org/briarproject/briar/media/CountingInputStream.java index 4f6063565..b3339fa13 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/CountingInputStream.java +++ b/briar-core/src/main/java/org/briarproject/briar/media/CountingInputStream.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.messaging; +package org.briarproject.briar.media; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; @@ -13,19 +13,19 @@ import javax.annotation.concurrent.NotThreadSafe; */ @NotThreadSafe @NotNullByDefault -class CountingInputStream extends InputStream { +public class CountingInputStream extends InputStream { private final InputStream delegate; private final long maxBytesToRead; private long bytesRead = 0; - CountingInputStream(InputStream delegate, long maxBytesToRead) { + public CountingInputStream(InputStream delegate, long maxBytesToRead) { this.delegate = delegate; this.maxBytesToRead = maxBytesToRead; } - long getBytesRead() { + public long getBytesRead() { return bytesRead; } diff --git a/briar-core/src/main/java/org/briarproject/briar/media/MediaConstants.java b/briar-core/src/main/java/org/briarproject/briar/media/MediaConstants.java new file mode 100644 index 000000000..4ac03bab0 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/media/MediaConstants.java @@ -0,0 +1,8 @@ +package org.briarproject.briar.media; + +public interface MediaConstants { + + // Metadata keys for messages + String MSG_KEY_CONTENT_TYPE = "contentType"; + String MSG_KEY_DESCRIPTOR_LENGTH = "descriptorLength"; +} diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingConstants.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingConstants.java index c9cb6b1eb..a280ba46a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingConstants.java @@ -9,8 +9,6 @@ interface MessagingConstants { String MSG_KEY_TIMESTAMP = "timestamp"; String MSG_KEY_LOCAL = "local"; String MSG_KEY_MSG_TYPE = "messageType"; - String MSG_KEY_CONTENT_TYPE = "contentType"; - String MSG_KEY_DESCRIPTOR_LENGTH = "descriptorLength"; String MSG_KEY_HAS_TEXT = "hasText"; String MSG_KEY_ATTACHMENT_HEADERS = "attachmentHeaders"; } diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java index c048e0034..1336dba7b 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java @@ -32,10 +32,10 @@ import org.briarproject.briar.api.client.MessageTracker.GroupCount; import org.briarproject.briar.api.conversation.ConversationManager.ConversationClient; import org.briarproject.briar.api.conversation.ConversationMessageHeader; import org.briarproject.briar.api.conversation.DeletionResult; -import org.briarproject.briar.api.messaging.Attachment; -import org.briarproject.briar.api.messaging.AttachmentHeader; -import org.briarproject.briar.api.messaging.FileTooBigException; -import org.briarproject.briar.api.messaging.InvalidAttachmentException; +import org.briarproject.briar.api.media.Attachment; +import org.briarproject.briar.api.media.AttachmentHeader; +import org.briarproject.briar.api.media.FileTooBigException; +import org.briarproject.briar.api.media.InvalidAttachmentException; import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.PrivateMessage; import org.briarproject.briar.api.messaging.PrivateMessageHeader; @@ -61,12 +61,12 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_L import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; import static org.briarproject.bramble.util.IoUtils.copyAndClose; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_CONTENT_TYPE; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; import static org.briarproject.briar.messaging.MessageTypes.ATTACHMENT; import static org.briarproject.briar.messaging.MessageTypes.PRIVATE_MESSAGE; import static org.briarproject.briar.messaging.MessagingConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_ATTACHMENT_HEADERS; -import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_CONTENT_TYPE; -import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_DESCRIPTOR_LENGTH; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_HAS_TEXT; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_MSG_TYPE; @@ -297,7 +297,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, try { BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn, g); - return new ContactId(meta.getLong("contactId").intValue()); + return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); } catch (FormatException e) { throw new DbException(e); } @@ -307,7 +307,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook, public ContactId getContactId(GroupId g) throws DbException { try { BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(g); - return new ContactId(meta.getLong("contactId").intValue()); + return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); } catch (FormatException e) { throw new DbException(e); } diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java index 467540a3c..6a4927077 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageFactoryImpl.java @@ -6,7 +6,7 @@ import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import org.briarproject.briar.api.messaging.PrivateMessage; import org.briarproject.briar.api.messaging.PrivateMessageFactory; diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java index 0b4909bf8..a1387d9f0 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/PrivateMessageValidator.java @@ -16,6 +16,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageContext; import org.briarproject.bramble.api.sync.validation.MessageValidator; import org.briarproject.bramble.api.system.Clock; +import org.briarproject.briar.media.CountingInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -31,11 +32,11 @@ import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACH import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_BYTES; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_CONTENT_TYPE; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; import static org.briarproject.briar.messaging.MessageTypes.ATTACHMENT; import static org.briarproject.briar.messaging.MessageTypes.PRIVATE_MESSAGE; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_ATTACHMENT_HEADERS; -import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_CONTENT_TYPE; -import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_DESCRIPTOR_LENGTH; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_HAS_TEXT; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_MSG_TYPE; diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/CountingInputStreamTest.java b/briar-core/src/test/java/org/briarproject/briar/media/CountingInputStreamTest.java similarity index 99% rename from briar-core/src/test/java/org/briarproject/briar/messaging/CountingInputStreamTest.java rename to briar-core/src/test/java/org/briarproject/briar/media/CountingInputStreamTest.java index 7c7d2b294..0d11a8408 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/CountingInputStreamTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/media/CountingInputStreamTest.java @@ -1,4 +1,4 @@ -package org.briarproject.briar.messaging; +package org.briarproject.briar.media; import org.briarproject.bramble.test.BrambleTestCase; import org.junit.Test; diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java index d07067887..7ad320e86 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java @@ -8,7 +8,7 @@ import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.api.forum.ForumPost; import org.briarproject.briar.api.forum.ForumPostFactory; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import org.briarproject.briar.api.messaging.PrivateMessage; import org.briarproject.briar.api.messaging.PrivateMessageFactory; import org.briarproject.briar.test.BriarTestCase; diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java index 352154e7b..6c214f032 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/MessagingManagerIntegrationTest.java @@ -8,7 +8,7 @@ import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.test.TestDatabaseConfigModule; import org.briarproject.briar.api.conversation.ConversationMessageHeader; import org.briarproject.briar.api.conversation.DeletionResult; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.PrivateMessage; import org.briarproject.briar.api.messaging.PrivateMessageFactory; diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/PrivateMessageValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/PrivateMessageValidatorTest.java index 1f0503f2b..24c95240a 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/PrivateMessageValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/PrivateMessageValidatorTest.java @@ -31,11 +31,11 @@ import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACH import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_BYTES; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH; import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_CONTENT_TYPE; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; import static org.briarproject.briar.messaging.MessageTypes.ATTACHMENT; import static org.briarproject.briar.messaging.MessageTypes.PRIVATE_MESSAGE; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_ATTACHMENT_HEADERS; -import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_CONTENT_TYPE; -import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_DESCRIPTOR_LENGTH; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_HAS_TEXT; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_LOCAL; import static org.briarproject.briar.messaging.MessagingConstants.MSG_KEY_MSG_TYPE; diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java index 3671c01e1..feff2346d 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java @@ -15,7 +15,7 @@ import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent; import org.briarproject.bramble.test.TestDatabaseConfigModule; import org.briarproject.bramble.test.TestTransportConnectionReader; import org.briarproject.bramble.test.TestTransportConnectionWriter; -import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.media.AttachmentHeader; import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.PrivateMessage; import org.briarproject.briar.api.messaging.PrivateMessageFactory; From 83ac866cc1ec1b051cbdba022c1333c4f3cc8b6a Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 20 Nov 2020 13:51:41 -0300 Subject: [PATCH 03/57] Implement AvatarManager with unit and integration tests --- .../briar/api/avatar/AvatarManager.java | 57 +++ .../api/avatar/event/AvatarUpdatedEvent.java | 33 ++ .../briar/avatar/AvatarConstants.java | 14 + .../briar/avatar/AvatarManagerImpl.java | 312 +++++++++++++++ .../briar/avatar/AvatarModule.java | 61 +++ .../briar/avatar/AvatarValidator.java | 96 +++++ .../briar/avatar/AvatarManagerImplTest.java | 368 ++++++++++++++++++ .../avatar/AvatarManagerIntegrationTest.java | 183 +++++++++ .../briar/avatar/AvatarValidatorTest.java | 188 +++++++++ .../IntroductionIntegrationTestComponent.java | 2 + .../test/BriarIntegrationTestComponent.java | 8 + 11 files changed, 1322 insertions(+) create mode 100644 briar-api/src/main/java/org/briarproject/briar/api/avatar/AvatarManager.java create mode 100644 briar-api/src/main/java/org/briarproject/briar/api/avatar/event/AvatarUpdatedEvent.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/avatar/AvatarConstants.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/avatar/AvatarManagerImpl.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/avatar/AvatarModule.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/avatar/AvatarValidator.java create mode 100644 briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java create mode 100644 briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerIntegrationTest.java create mode 100644 briar-core/src/test/java/org/briarproject/briar/avatar/AvatarValidatorTest.java diff --git a/briar-api/src/main/java/org/briarproject/briar/api/avatar/AvatarManager.java b/briar-api/src/main/java/org/briarproject/briar/api/avatar/AvatarManager.java new file mode 100644 index 000000000..aee40c85e --- /dev/null +++ b/briar-api/src/main/java/org/briarproject/briar/api/avatar/AvatarManager.java @@ -0,0 +1,57 @@ +package org.briarproject.briar.api.avatar; + +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.ClientId; +import org.briarproject.briar.api.media.Attachment; +import org.briarproject.briar.api.media.AttachmentHeader; + +import java.io.IOException; +import java.io.InputStream; + +import javax.annotation.Nullable; + +@NotNullByDefault +public interface AvatarManager { + + /** + * The unique ID of the avatar client. + */ + ClientId CLIENT_ID = new ClientId("org.briarproject.briar.avatar"); + + /** + * The current major version of the avatar client. + */ + int MAJOR_VERSION = 0; + + /** + * The current minor version of the avatar client. + */ + int MINOR_VERSION = 0; + + /** + * Store a new profile image represented by the given InputStream + * and share it with all contacts. + */ + AttachmentHeader addAvatar(String contentType, InputStream in) + throws DbException, IOException; + + /** + * Returns the current known profile image header for the given contact + * or null if none is known. + */ + @Nullable + AttachmentHeader getAvatarHeader(Contact c) throws DbException; + + /** + * Returns our current profile image header or null if none has been added. + */ + @Nullable + AttachmentHeader getMyAvatarHeader() throws DbException; + + /** + * Returns the profile image attachment for the given header. + */ + Attachment getAvatar(AttachmentHeader h) throws DbException; +} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/avatar/event/AvatarUpdatedEvent.java b/briar-api/src/main/java/org/briarproject/briar/api/avatar/event/AvatarUpdatedEvent.java new file mode 100644 index 000000000..105e487e8 --- /dev/null +++ b/briar-api/src/main/java/org/briarproject/briar/api/avatar/event/AvatarUpdatedEvent.java @@ -0,0 +1,33 @@ +package org.briarproject.briar.api.avatar.event; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.briar.api.media.AttachmentHeader; + +import javax.annotation.concurrent.Immutable; + +/** + * An event that is broadcast when a new avatar is received. + */ +@Immutable +@NotNullByDefault +public class AvatarUpdatedEvent extends Event { + + private final ContactId contactId; + private final AttachmentHeader attachmentHeader; + + public AvatarUpdatedEvent(ContactId contactId, + AttachmentHeader attachmentHeader) { + this.contactId = contactId; + this.attachmentHeader = attachmentHeader; + } + + public ContactId getContactId() { + return contactId; + } + + public AttachmentHeader getAttachmentHeader() { + return attachmentHeader; + } +} diff --git a/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarConstants.java b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarConstants.java new file mode 100644 index 000000000..56c4163b7 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarConstants.java @@ -0,0 +1,14 @@ +package org.briarproject.briar.avatar; + +interface AvatarConstants { + + // Message type constants + int MSG_TYPE_UPDATE = 0; + + // Metadata keys for groups + String GROUP_KEY_CONTACT_ID = "contactId"; + + // Message metadata keys + String MSG_KEY_VERSION = "version"; + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarManagerImpl.java new file mode 100644 index 000000000..5e8818d14 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarManagerImpl.java @@ -0,0 +1,312 @@ +package org.briarproject.briar.avatar; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.ContactManager.ContactHook; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.data.MetadataParser; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Metadata; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; +import org.briarproject.bramble.api.lifecycle.LifecycleManager.OpenDatabaseHook; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.Group.Visibility; +import org.briarproject.bramble.api.sync.GroupFactory; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.InvalidMessageException; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.sync.validation.IncomingMessageHook; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.versioning.ClientVersioningManager; +import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; +import org.briarproject.briar.api.avatar.AvatarManager; +import org.briarproject.briar.api.avatar.event.AvatarUpdatedEvent; +import org.briarproject.briar.api.media.Attachment; +import org.briarproject.briar.api.media.AttachmentHeader; +import org.briarproject.briar.api.media.FileTooBigException; +import org.briarproject.briar.api.media.InvalidAttachmentException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; +import static org.briarproject.bramble.util.IoUtils.copyAndClose; +import static org.briarproject.briar.avatar.AvatarConstants.GROUP_KEY_CONTACT_ID; +import static org.briarproject.briar.avatar.AvatarConstants.MSG_KEY_VERSION; +import static org.briarproject.briar.avatar.AvatarConstants.MSG_TYPE_UPDATE; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_CONTENT_TYPE; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; + +@Immutable +@NotNullByDefault +class AvatarManagerImpl implements AvatarManager, OpenDatabaseHook, ContactHook, + ClientVersioningHook, IncomingMessageHook { + + private final DatabaseComponent db; + private final IdentityManager identityManager; + private final ClientHelper clientHelper; + private final ClientVersioningManager clientVersioningManager; + private final MetadataParser metadataParser; + private final GroupFactory groupFactory; + private final Clock clock; + + @Inject + AvatarManagerImpl( + DatabaseComponent db, + IdentityManager identityManager, + ClientHelper clientHelper, + ClientVersioningManager clientVersioningManager, + MetadataParser metadataParser, + GroupFactory groupFactory, + Clock clock) { + this.db = db; + this.identityManager = identityManager; + this.clientHelper = clientHelper; + this.clientVersioningManager = clientVersioningManager; + this.metadataParser = metadataParser; + this.groupFactory = groupFactory; + this.clock = clock; + } + + @Override + public void onDatabaseOpened(Transaction txn) throws DbException { + // Create our avatar group if necessary + LocalAuthor a = identityManager.getLocalAuthor(txn); + Group ourGroup = getGroup(a.getId()); + if (db.containsGroup(txn, ourGroup.getId())) return; + db.addGroup(txn, ourGroup); + + // Set things up for any pre-existing contacts + for (Contact c : db.getContacts(txn)) addingContact(txn, c); + } + + @Override + public void addingContact(Transaction txn, Contact c) throws DbException { + // Create a group to share with the contact + Group theirGroup = getGroup(c.getAuthor().getId()); + db.addGroup(txn, theirGroup); + // Attach the contact ID to the group + BdfDictionary d = new BdfDictionary(); + d.put(GROUP_KEY_CONTACT_ID, c.getId().getInt()); + try { + clientHelper.mergeGroupMetadata(txn, theirGroup.getId(), d); + } catch (FormatException e) { + throw new AssertionError(e); + } + // Apply the client's visibility to our and their group + Group ourGroup = getOurGroup(txn); + Visibility client = clientVersioningManager.getClientVisibility(txn, + c.getId(), CLIENT_ID, MAJOR_VERSION); + db.setGroupVisibility(txn, c.getId(), ourGroup.getId(), client); + db.setGroupVisibility(txn, c.getId(), theirGroup.getId(), client); + } + + @Override + public void removingContact(Transaction txn, Contact c) throws DbException { + db.removeGroup(txn, getGroup(c.getAuthor().getId())); + } + + @Override + public void onClientVisibilityChanging(Transaction txn, Contact c, + Visibility v) throws DbException { + // Apply the client's visibility to our and the contact group + Group ourGroup = getOurGroup(txn); + Group theirGroup = getGroup(c.getAuthor().getId()); + db.setGroupVisibility(txn, c.getId(), ourGroup.getId(), v); + db.setGroupVisibility(txn, c.getId(), theirGroup.getId(), v); + } + + @Override + public boolean incomingMessage(Transaction txn, Message m, Metadata meta) + throws DbException, InvalidMessageException { + try { + // Find the latest update, if any + BdfDictionary d = metadataParser.parse(meta); + LatestUpdate latest = findLatest(txn, m.getGroupId()); + if (latest != null) { + if (d.getLong(MSG_KEY_VERSION) > latest.version) { + // This update is newer - delete the previous update + db.deleteMessage(txn, latest.messageId); + db.deleteMessageMetadata(txn, latest.messageId); + } else { + // We've already received a newer update - delete this one + db.deleteMessage(txn, m.getId()); + db.deleteMessageMetadata(txn, m.getId()); + return false; // don't broadcast update + } + } + ContactId contactId = getContactId(txn, m.getGroupId()); + String contentType = d.getString(MSG_KEY_CONTENT_TYPE); + AttachmentHeader a = new AttachmentHeader(m.getId(), contentType); + txn.attach(new AvatarUpdatedEvent(contactId, a)); + } catch (FormatException e) { + throw new InvalidMessageException(e); + } + return false; + } + + @Override + public AttachmentHeader addAvatar(String contentType, InputStream in) + throws DbException, IOException { + // find latest avatar + GroupId groupId; + LatestUpdate latest; + Transaction txn = db.startTransaction(true); + try { + groupId = getOurGroup(txn).getId(); + // TODO this might not be the latest anymore at the end of this method + // Can we run everything in one transaction? Probably not. + latest = findLatest(txn, groupId); + db.commitTransaction(txn); + } finally { + db.endTransaction(txn); + } + long version = latest == null ? 0 : latest.version + 1; + // 0.0: Message Type, Version, Content-Type + // TODO do we need to add the message type explicitly? + BdfList list = BdfList.of(MSG_TYPE_UPDATE, version, contentType); + byte[] descriptor = clientHelper.toByteArray(list); + // add BdfList and stream content to body + ByteArrayOutputStream bodyOut = new ByteArrayOutputStream(); + bodyOut.write(descriptor); + copyAndClose(in, bodyOut); + if (bodyOut.size() > MAX_MESSAGE_BODY_LENGTH) + throw new FileTooBigException(); + // assemble message + byte[] body = bodyOut.toByteArray(); + long timestamp = clock.currentTimeMillis(); + Message m = clientHelper.createMessage(groupId, timestamp, body); + // add metadata to message + BdfDictionary meta = new BdfDictionary(); + meta.put(MSG_KEY_VERSION, version); + meta.put(MSG_KEY_CONTENT_TYPE, contentType); + meta.put(MSG_KEY_DESCRIPTOR_LENGTH, descriptor.length); + // send message + db.transaction(false, txn2 -> { + if (latest != null) { + // delete previous update + db.deleteMessage(txn2, latest.messageId); + db.deleteMessageMetadata(txn2, latest.messageId); + } + clientHelper.addLocalMessage(txn2, m, meta, true, false); + }); + return new AttachmentHeader(m.getId(), contentType); + } + + @Nullable + @Override + public AttachmentHeader getAvatarHeader(Contact c) throws DbException { + try { + Group g = getGroup(c.getAuthor().getId()); + return db.transactionWithNullableResult(true, txn -> + getAvatarHeader(txn, g.getId()) + ); + } catch (FormatException e) { + throw new DbException(e); + } + } + + @Nullable + @Override + public AttachmentHeader getMyAvatarHeader() throws DbException { + try { + return db.transactionWithNullableResult(true, txn -> { + Group g = getOurGroup(txn); + return getAvatarHeader(txn, g.getId()); + }); + } catch (FormatException e) { + throw new DbException(e); + } + } + + @Nullable + private AttachmentHeader getAvatarHeader(Transaction txn, GroupId groupId) + throws DbException, FormatException { + LatestUpdate latest = findLatest(txn, groupId); + if (latest == null) return null; + return new AttachmentHeader(latest.messageId, latest.contentType); + } + + @Override + public Attachment getAvatar(AttachmentHeader h) throws DbException { + MessageId m = h.getMessageId(); + byte[] body = clientHelper.getMessage(m).getBody(); + try { + BdfDictionary meta = clientHelper.getMessageMetadataAsDictionary(m); + String contentType = meta.getString(MSG_KEY_CONTENT_TYPE); + if (!contentType.equals(h.getContentType())) + throw new InvalidAttachmentException(); + int offset = meta.getLong(MSG_KEY_DESCRIPTOR_LENGTH).intValue(); + return new Attachment(h, new ByteArrayInputStream(body, offset, + body.length - offset)); + } catch (FormatException e) { + throw new DbException(e); + } + } + + @Nullable + private LatestUpdate findLatest(Transaction txn, GroupId g) + throws DbException, FormatException { + Map metadata = + clientHelper.getMessageMetadataAsDictionary(txn, g); + for (Map.Entry e : metadata.entrySet()) { + BdfDictionary meta = e.getValue(); + long version = meta.getLong(MSG_KEY_VERSION); + String contentType = meta.getString(MSG_KEY_CONTENT_TYPE); + return new LatestUpdate(e.getKey(), version, contentType); + } + return null; + } + + private ContactId getContactId(Transaction txn, GroupId g) + throws DbException { + try { + BdfDictionary meta = + clientHelper.getGroupMetadataAsDictionary(txn, g); + return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); + } catch (FormatException e) { + throw new DbException(e); + } + } + + private Group getOurGroup(Transaction txn) throws DbException { + LocalAuthor a = identityManager.getLocalAuthor(txn); + return getGroup(a.getId()); + } + + private Group getGroup(AuthorId authorId) { + return groupFactory + .createGroup(CLIENT_ID, MAJOR_VERSION, authorId.getBytes()); + } + + private static class LatestUpdate { + + private final MessageId messageId; + private final long version; + private final String contentType; + + private LatestUpdate(MessageId messageId, long version, + String contentType) { + this.messageId = messageId; + this.version = version; + this.contentType = contentType; + } + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarModule.java b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarModule.java new file mode 100644 index 000000000..446e21437 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarModule.java @@ -0,0 +1,61 @@ +package org.briarproject.briar.avatar; + +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.data.BdfReaderFactory; +import org.briarproject.bramble.api.data.MetadataEncoder; +import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.sync.validation.ValidationManager; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.versioning.ClientVersioningManager; +import org.briarproject.briar.api.avatar.AvatarManager; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +import static org.briarproject.briar.api.avatar.AvatarManager.CLIENT_ID; +import static org.briarproject.briar.api.avatar.AvatarManager.MAJOR_VERSION; +import static org.briarproject.briar.api.avatar.AvatarManager.MINOR_VERSION; + +@Module +public class AvatarModule { + + public static class EagerSingletons { + @Inject + AvatarValidator avatarValidator; + @Inject + AvatarManager avatarManager; + } + + @Provides + @Singleton + AvatarValidator provideAvatarValidator(ValidationManager validationManager, + BdfReaderFactory bdfReaderFactory, MetadataEncoder metadataEncoder, + Clock clock) { + AvatarValidator introductionValidator = + new AvatarValidator(bdfReaderFactory, metadataEncoder, clock); + validationManager.registerMessageValidator(CLIENT_ID, MAJOR_VERSION, + introductionValidator); + return introductionValidator; + } + + @Provides + @Singleton + AvatarManager provideAvatarManager( + LifecycleManager lifecycleManager, + ContactManager contactManager, + ValidationManager validationManager, + ClientVersioningManager clientVersioningManager, + AvatarManagerImpl avatarManager) { + lifecycleManager.registerOpenDatabaseHook(avatarManager); + contactManager.registerContactHook(avatarManager); + validationManager.registerIncomingMessageHook(CLIENT_ID, + MAJOR_VERSION, avatarManager); + clientVersioningManager.registerClient(CLIENT_ID, + MAJOR_VERSION, MINOR_VERSION, avatarManager); + return avatarManager; + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarValidator.java b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarValidator.java new file mode 100644 index 000000000..ac2e91ca1 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarValidator.java @@ -0,0 +1,96 @@ +package org.briarproject.briar.avatar; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.data.BdfReader; +import org.briarproject.bramble.api.data.BdfReaderFactory; +import org.briarproject.bramble.api.data.MetadataEncoder; +import org.briarproject.bramble.api.db.Metadata; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.InvalidMessageException; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageContext; +import org.briarproject.bramble.api.sync.validation.MessageValidator; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.briar.media.CountingInputStream; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.annotation.concurrent.Immutable; + +import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; +import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; +import static org.briarproject.bramble.util.ValidationUtils.checkLength; +import static org.briarproject.bramble.util.ValidationUtils.checkSize; +import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_BYTES; +import static org.briarproject.briar.avatar.AvatarConstants.MSG_KEY_VERSION; +import static org.briarproject.briar.avatar.AvatarConstants.MSG_TYPE_UPDATE; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_CONTENT_TYPE; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; + +@Immutable +@NotNullByDefault +class AvatarValidator implements MessageValidator { + + private final BdfReaderFactory bdfReaderFactory; + private final MetadataEncoder metadataEncoder; + private final Clock clock; + + AvatarValidator(BdfReaderFactory bdfReaderFactory, + MetadataEncoder metadataEncoder, Clock clock) { + this.bdfReaderFactory = bdfReaderFactory; + this.metadataEncoder = metadataEncoder; + this.clock = clock; + } + + @Override + public MessageContext validateMessage(Message m, Group g) + throws InvalidMessageException { + // Reject the message if it's too far in the future + long now = clock.currentTimeMillis(); + if (m.getTimestamp() - now > MAX_CLOCK_DIFFERENCE) { + throw new InvalidMessageException( + "Timestamp is too far in the future"); + } + try { + InputStream in = new ByteArrayInputStream(m.getBody()); + CountingInputStream countIn = + new CountingInputStream(in, MAX_MESSAGE_BODY_LENGTH); + BdfReader reader = bdfReaderFactory.createReader(countIn); + BdfList list = reader.readList(); + long bytesRead = countIn.getBytesRead(); + BdfDictionary d = validateUpdate(list, bytesRead); + Metadata meta = metadataEncoder.encode(d); + return new MessageContext(meta); + } catch (IOException e) { + throw new InvalidMessageException(e); + } + } + + private BdfDictionary validateUpdate(BdfList body, long descriptorLength) + throws FormatException { + // 0.0: Message Type, Version, Content-Type + checkSize(body, 3); + // Message Type + long messageType = body.getLong(0); + if (messageType != MSG_TYPE_UPDATE) throw new FormatException(); + // Version + long version = body.getLong(1); + if (version < 0) throw new FormatException(); + // Content-Type + String contentType = body.getString(2); + checkLength(contentType, 1, MAX_CONTENT_TYPE_BYTES); + + // Return the metadata + BdfDictionary meta = new BdfDictionary(); + meta.put(MSG_KEY_VERSION, version); + meta.put(MSG_KEY_CONTENT_TYPE, contentType); + meta.put(MSG_KEY_DESCRIPTOR_LENGTH, descriptorLength); + return meta; + } + +} diff --git a/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java new file mode 100644 index 000000000..b83c063a1 --- /dev/null +++ b/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java @@ -0,0 +1,368 @@ +package org.briarproject.briar.avatar; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactId; +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.MetadataParser; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.EventAction; +import org.briarproject.bramble.api.db.Metadata; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; +import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.Group.Visibility; +import org.briarproject.bramble.api.sync.GroupFactory; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.InvalidMessageException; +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.versioning.ClientVersioningManager; +import org.briarproject.bramble.test.BrambleMockTestCase; +import org.briarproject.bramble.test.DbExpectations; +import org.briarproject.briar.api.avatar.event.AvatarUpdatedEvent; +import org.briarproject.briar.api.media.AttachmentHeader; +import org.jmock.Expectations; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Nullable; + +import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; +import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; +import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; +import static org.briarproject.bramble.test.TestUtils.getContact; +import static org.briarproject.bramble.test.TestUtils.getGroup; +import static org.briarproject.bramble.test.TestUtils.getLocalAuthor; +import static org.briarproject.bramble.test.TestUtils.getMessage; +import static org.briarproject.bramble.test.TestUtils.getRandomBytes; +import static org.briarproject.bramble.test.TestUtils.getRandomId; +import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.avatar.AvatarManager.CLIENT_ID; +import static org.briarproject.briar.api.avatar.AvatarManager.MAJOR_VERSION; +import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_BYTES; +import static org.briarproject.briar.avatar.AvatarConstants.GROUP_KEY_CONTACT_ID; +import static org.briarproject.briar.avatar.AvatarConstants.MSG_KEY_VERSION; +import static org.briarproject.briar.avatar.AvatarConstants.MSG_TYPE_UPDATE; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_CONTENT_TYPE; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +public class AvatarManagerImplTest extends BrambleMockTestCase { + + private final DatabaseComponent db = context.mock(DatabaseComponent.class); + private final IdentityManager identityManager = + context.mock(IdentityManager.class); + private final ClientHelper clientHelper = context.mock(ClientHelper.class); + private final ClientVersioningManager clientVersioningManager = + context.mock(ClientVersioningManager.class); + private final MetadataParser metadataParser = + context.mock(MetadataParser.class); + private final GroupFactory groupFactory = context.mock(GroupFactory.class); + private final Clock clock = context.mock(Clock.class); + + private final Group localGroup = getGroup(CLIENT_ID, MAJOR_VERSION); + private final GroupId localGroupId = localGroup.getId(); + private final LocalAuthor localAuthor = getLocalAuthor(); + private final Contact contact = getContact(); + private final Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION, 32); + private final GroupId contactGroupId = contactGroup.getId(); + private final Message ourMsg = getMessage(localGroupId); + private final Message contactMsg = getMessage(contactGroupId); + private final Metadata meta = new Metadata(); + private final String contentType = getRandomString(MAX_CONTENT_TYPE_BYTES); + private final BdfDictionary metaDict = BdfDictionary.of( + new BdfEntry(MSG_KEY_VERSION, 1), + new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType) + ); + + private final AvatarManagerImpl avatarManager = + new AvatarManagerImpl(db, identityManager, clientHelper, + clientVersioningManager, metadataParser, groupFactory, + clock); + + @Test + public void testOpenDatabaseHook() throws DbException, FormatException { + Transaction txn = new Transaction(null, false); + + // local group already exists, so nothing more to do + expectCreateGroup(localAuthor.getId(), localGroup); + context.checking(new Expectations() {{ + oneOf(identityManager).getLocalAuthor(txn); + will(returnValue(localAuthor)); + oneOf(db).containsGroup(txn, localGroupId); + will(returnValue(true)); + }}); + avatarManager.onDatabaseOpened(txn); + + // local group does not exist, so we need to set things up for contacts + expectCreateGroup(localAuthor.getId(), localGroup); + context.checking(new Expectations() {{ + oneOf(identityManager).getLocalAuthor(txn); + will(returnValue(localAuthor)); + oneOf(db).containsGroup(txn, localGroupId); + will(returnValue(false)); + oneOf(db).addGroup(txn, localGroup); + oneOf(db).getContacts(txn); + will(returnValue(Collections.singletonList(contact))); + }}); + expectAddingContact(txn, contact, SHARED); + avatarManager.onDatabaseOpened(txn); + } + + @Test + public void testAddingContact() throws DbException, FormatException { + Transaction txn = new Transaction(null, false); + + expectAddingContact(txn, contact, INVISIBLE); + avatarManager.addingContact(txn, contact); + + Contact contact2 = getContact(); + expectAddingContact(txn, contact2, VISIBLE); + avatarManager.addingContact(txn, contact2); + } + + @Test + public void testRemovingContact() throws DbException { + Transaction txn = new Transaction(null, false); + + expectCreateGroup(contact.getAuthor().getId(), contactGroup); + context.checking(new Expectations() {{ + oneOf(db).removeGroup(txn, contactGroup); + }}); + + avatarManager.removingContact(txn, contact); + } + + @Test + public void testOnClientVisibilityChanging() throws DbException { + Transaction txn = new Transaction(null, false); + + expectGetOurGroup(txn); + expectCreateGroup(contact.getAuthor().getId(), contactGroup); + expectSetGroupVisibility(txn, contact.getId(), localGroupId, VISIBLE); + expectSetGroupVisibility(txn, contact.getId(), contactGroupId, VISIBLE); + avatarManager.onClientVisibilityChanging(txn, contact, VISIBLE); + + expectGetOurGroup(txn); + expectCreateGroup(contact.getAuthor().getId(), contactGroup); + expectSetGroupVisibility(txn, contact.getId(), localGroupId, SHARED); + expectSetGroupVisibility(txn, contact.getId(), contactGroupId, SHARED); + avatarManager.onClientVisibilityChanging(txn, contact, SHARED); + + expectGetOurGroup(txn); + expectCreateGroup(contact.getAuthor().getId(), contactGroup); + expectSetGroupVisibility(txn, contact.getId(), localGroupId, INVISIBLE); + expectSetGroupVisibility(txn, contact.getId(), contactGroupId, + INVISIBLE); + avatarManager.onClientVisibilityChanging(txn, contact, INVISIBLE); + } + + @Test + public void testFirstIncomingMessage() + throws DbException, InvalidMessageException, FormatException { + Transaction txn = new Transaction(null, false); + BdfDictionary d = BdfDictionary.of( + new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType) + ); + + context.checking(new Expectations() {{ + oneOf(metadataParser).parse(meta); + will(returnValue(d)); + }}); + expectFindLatest(txn, contactGroupId, new MessageId(getRandomId()), + null); + expectGetContactId(txn, contactGroupId, contact.getId()); + + assertFalse(avatarManager.incomingMessage(txn, contactMsg, meta)); + assertEquals(1, txn.getActions().size()); + Event event = ((EventAction) txn.getActions().get(0)).getEvent(); + AvatarUpdatedEvent avatarUpdatedEvent = (AvatarUpdatedEvent) event; + assertEquals(contactMsg.getId(), + avatarUpdatedEvent.getAttachmentHeader().getMessageId()); + assertEquals(contact.getId(), avatarUpdatedEvent.getContactId()); + } + + @Test + public void testNewerIncomingMessage() + throws DbException, InvalidMessageException, FormatException { + Transaction txn = new Transaction(null, false); + BdfDictionary d = BdfDictionary.of( + new BdfEntry(MSG_KEY_VERSION, 1), + new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType) + ); + MessageId latestMsgId = new MessageId(getRandomId()); + BdfDictionary latest = BdfDictionary.of( + new BdfEntry(MSG_KEY_VERSION, 0), + new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType) + ); + + context.checking(new Expectations() {{ + oneOf(metadataParser).parse(meta); + will(returnValue(d)); + // delete old "latest" message + oneOf(db).deleteMessage(txn, latestMsgId); + oneOf(db).deleteMessageMetadata(txn, latestMsgId); + }}); + expectFindLatest(txn, contactGroupId, latestMsgId, latest); + expectGetContactId(txn, contactGroupId, contact.getId()); + + assertFalse(avatarManager.incomingMessage(txn, contactMsg, meta)); + + // event to broadcast + assertEquals(1, txn.getActions().size()); + } + + @Test + public void testDeleteOlderIncomingMessage() + throws DbException, InvalidMessageException, FormatException { + Transaction txn = new Transaction(null, false); + BdfDictionary d = BdfDictionary.of( + new BdfEntry(MSG_KEY_VERSION, 0), + new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType) + ); + MessageId latestMsgId = new MessageId(getRandomId()); + BdfDictionary latest = BdfDictionary.of( + new BdfEntry(MSG_KEY_VERSION, 1), + new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType) + ); + + context.checking(new Expectations() {{ + oneOf(metadataParser).parse(meta); + will(returnValue(d)); + // delete older incoming message + oneOf(db).deleteMessage(txn, contactMsg.getId()); + oneOf(db).deleteMessageMetadata(txn, contactMsg.getId()); + }}); + expectFindLatest(txn, contactGroupId, latestMsgId, latest); + + assertFalse(avatarManager.incomingMessage(txn, contactMsg, meta)); + + // no event to broadcast + assertEquals(0, txn.getActions().size()); + } + + @Test + public void testAddAvatar() throws Exception { + byte[] avatarBytes = getRandomBytes(42); + InputStream inputStream = new ByteArrayInputStream(avatarBytes); + Transaction txn = new Transaction(null, true); + Transaction txn2 = new Transaction(null, false); + long latestVersion = metaDict.getLong(MSG_KEY_VERSION); + long version = latestVersion + 1; + BdfList list = BdfList.of(MSG_TYPE_UPDATE, version, contentType); + long now = System.currentTimeMillis(); + Message newMsg = getMessage(localGroupId); + BdfDictionary newMeta = BdfDictionary.of( + new BdfEntry(MSG_KEY_VERSION, version), + new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType), + new BdfEntry(MSG_KEY_DESCRIPTOR_LENGTH, 0) + ); + context.checking(new DbExpectations() {{ + oneOf(db).startTransaction(true); + will(returnValue(txn)); + oneOf(db).commitTransaction(txn); + oneOf(db).endTransaction(txn); + oneOf(clientHelper).toByteArray(list); + oneOf(clock).currentTimeMillis(); + will(returnValue(now)); + oneOf(clientHelper).createMessage(with(equal(localGroupId)), + with(equal(now)), with(any(byte[].class))); + will(returnValue(newMsg)); + oneOf(db).transaction(with(false), withDbRunnable(txn2)); + oneOf(db).deleteMessage(txn2, ourMsg.getId()); + oneOf(db).deleteMessageMetadata(txn2, ourMsg.getId()); + oneOf(clientHelper) + .addLocalMessage(txn2, newMsg, newMeta, true, false); + }}); + expectGetOurGroup(txn); + expectFindLatest(txn, localGroupId, ourMsg.getId(), metaDict); + + AttachmentHeader header = + avatarManager.addAvatar(contentType, inputStream); + assertEquals(newMsg.getId(), header.getMessageId()); + assertEquals(contentType, header.getContentType()); + } + + private void expectGetContactId(Transaction txn, GroupId groupId, + ContactId contactId) throws DbException, FormatException { + BdfDictionary d = BdfDictionary + .of(new BdfEntry(GROUP_KEY_CONTACT_ID, contactId.getInt())); + context.checking(new Expectations() {{ + oneOf(clientHelper).getGroupMetadataAsDictionary(txn, groupId); + will(returnValue(d)); + }}); + } + + private void expectFindLatest(Transaction txn, GroupId groupId, + MessageId messageId, @Nullable BdfDictionary d) + throws DbException, FormatException { + Map map = new HashMap<>(); + if (d != null) map.put(messageId, d); + context.checking(new Expectations() {{ + oneOf(clientHelper) + .getMessageMetadataAsDictionary(txn, groupId); + will(returnValue(map)); + }}); + } + + private void expectSetGroupVisibility(Transaction txn, ContactId contactId, + GroupId groupId, Visibility v) throws DbException { + context.checking(new Expectations() {{ + oneOf(db).setGroupVisibility(txn, contactId, groupId, v); + }}); + } + + private void expectAddingContact(Transaction txn, Contact c, Visibility v) + throws DbException, FormatException { + BdfDictionary groupMeta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_ID, c.getId().getInt()) + ); + expectGetOurGroup(txn); + context.checking(new Expectations() {{ + oneOf(groupFactory).createGroup(CLIENT_ID, MAJOR_VERSION, + c.getAuthor().getId().getBytes()); + will(returnValue(contactGroup)); + oneOf(db).addGroup(txn, contactGroup); + oneOf(clientHelper) + .mergeGroupMetadata(txn, contactGroupId, groupMeta); + oneOf(clientVersioningManager) + .getClientVisibility(txn, c.getId(), CLIENT_ID, + MAJOR_VERSION); + will(returnValue(v)); + }}); + expectSetGroupVisibility(txn, c.getId(), localGroupId, v); + expectSetGroupVisibility(txn, c.getId(), contactGroupId, v); + } + + private void expectGetOurGroup(Transaction txn) throws DbException { + context.checking(new Expectations() {{ + oneOf(identityManager).getLocalAuthor(txn); + will(returnValue(localAuthor)); + }}); + expectCreateGroup(localAuthor.getId(), localGroup); + } + + private void expectCreateGroup(AuthorId authorId, Group group) { + context.checking(new Expectations() {{ + oneOf(groupFactory) + .createGroup(CLIENT_ID, MAJOR_VERSION, authorId.getBytes()); + will(returnValue(group)); + }}); + } + +} diff --git a/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerIntegrationTest.java new file mode 100644 index 000000000..08f6a0485 --- /dev/null +++ b/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerIntegrationTest.java @@ -0,0 +1,183 @@ +package org.briarproject.briar.avatar; + +import org.briarproject.bramble.test.TestDatabaseConfigModule; +import org.briarproject.briar.api.avatar.AvatarManager; +import org.briarproject.briar.api.media.Attachment; +import org.briarproject.briar.api.media.AttachmentHeader; +import org.briarproject.briar.test.BriarIntegrationTest; +import org.briarproject.briar.test.BriarIntegrationTestComponent; +import org.briarproject.briar.test.DaggerBriarIntegrationTestComponent; +import org.junit.Before; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import static org.briarproject.bramble.test.TestUtils.getRandomBytes; +import static org.briarproject.bramble.util.IoUtils.copyAndClose; +import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_BYTES; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class AvatarManagerIntegrationTest + extends BriarIntegrationTest { + + private AvatarManager avatarManager0, avatarManager1; + + private final String contentType = getRandomString(MAX_CONTENT_TYPE_BYTES); + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + avatarManager0 = c0.getAvatarManager(); + avatarManager1 = c1.getAvatarManager(); + } + + @Override + protected void createComponents() { + BriarIntegrationTestComponent component = + DaggerBriarIntegrationTestComponent.builder().build(); + BriarIntegrationTestComponent.Helper.injectEagerSingletons(component); + component.inject(this); + + c0 = DaggerBriarIntegrationTestComponent.builder() + .testDatabaseConfigModule(new TestDatabaseConfigModule(t0Dir)) + .build(); + BriarIntegrationTestComponent.Helper.injectEagerSingletons(c0); + + c1 = DaggerBriarIntegrationTestComponent.builder() + .testDatabaseConfigModule(new TestDatabaseConfigModule(t1Dir)) + .build(); + BriarIntegrationTestComponent.Helper.injectEagerSingletons(c1); + + c2 = DaggerBriarIntegrationTestComponent.builder() + .testDatabaseConfigModule(new TestDatabaseConfigModule(t2Dir)) + .build(); + BriarIntegrationTestComponent.Helper.injectEagerSingletons(c2); + } + + @Test + public void testAddingAndSyncAvatars() throws Exception { + // Both contacts don't have avatars + assertNull(avatarManager0.getMyAvatarHeader()); + assertNull(avatarManager1.getMyAvatarHeader()); + + // Both contacts don't see avatars for each other + assertNull(avatarManager0.getAvatarHeader(contact1From0)); + assertNull(avatarManager1.getAvatarHeader(contact0From1)); + + // 0 adds avatar + byte[] avatar0bytes = getRandomBytes(42); + InputStream avatar0inputStream = new ByteArrayInputStream(avatar0bytes); + AttachmentHeader header0 = + avatarManager0.addAvatar(contentType, avatar0inputStream); + assertEquals(contentType, header0.getContentType()); + + // 0 sees their own avatar + header0 = avatarManager0.getMyAvatarHeader(); + assertNotNull(header0); + assertEquals(contentType, header0.getContentType()); + assertNotNull(header0.getMessageId()); + + // 0 can retrieve their own avatar + Attachment attachment0 = avatarManager0.getAvatar(header0); + assertEquals(contentType, attachment0.getHeader().getContentType()); + assertStreamMatches(avatar0bytes, attachment0.getStream()); + + // send the avatar from 0 to 1 + sync0To1(1, true); + + // 1 also sees 0's avatar now + AttachmentHeader header0From1 = + avatarManager1.getAvatarHeader(contact0From1); + assertNotNull(header0From1); + assertEquals(contentType, header0From1.getContentType()); + assertNotNull(header0From1.getMessageId()); + + // 1 can retrieve 0's avatar + Attachment attachment0From1 = avatarManager1.getAvatar(header0From1); + assertEquals(contentType, + attachment0From1.getHeader().getContentType()); + assertStreamMatches(avatar0bytes, attachment0From1.getStream()); + + // 1 also adds avatar + String contentType1 = getRandomString(MAX_CONTENT_TYPE_BYTES); + byte[] avatar1bytes = getRandomBytes(42); + InputStream avatar1inputStream = new ByteArrayInputStream(avatar1bytes); + avatarManager1.addAvatar(contentType1, avatar1inputStream); + + // send the avatar from 1 to 0 + sync1To0(1, true); + + // 0 sees 1's avatar now + AttachmentHeader header1From0 = + avatarManager0.getAvatarHeader(contact1From0); + assertNotNull(header1From0); + assertEquals(contentType1, header1From0.getContentType()); + assertNotNull(header1From0.getMessageId()); + + // 0 can retrieve 1's avatar + Attachment attachment1From0 = avatarManager0.getAvatar(header1From0); + assertEquals(contentType1, + attachment1From0.getHeader().getContentType()); + assertStreamMatches(avatar1bytes, attachment1From0.getStream()); + } + + @Test + public void testUpdatingAvatars() throws Exception { + // 0 adds avatar + byte[] avatar0bytes = getRandomBytes(42); + InputStream avatar0inputStream = new ByteArrayInputStream(avatar0bytes); + avatarManager0.addAvatar(contentType, avatar0inputStream); + + // 0 can retrieve their own avatar + AttachmentHeader header0 = avatarManager0.getMyAvatarHeader(); + assertNotNull(header0); + Attachment attachment0 = avatarManager0.getAvatar(header0); + assertStreamMatches(avatar0bytes, attachment0.getStream()); + + // send the avatar from 0 to 1 + sync0To1(1, true); + + // 1 only sees 0's avatar + AttachmentHeader header0From1 = + avatarManager1.getAvatarHeader(contact0From1); + assertNotNull(header0From1); + Attachment attachment0From1 = avatarManager1.getAvatar(header0From1); + assertStreamMatches(avatar0bytes, attachment0From1.getStream()); + + // 0 adds a new avatar + byte[] avatar0bytes2 = getRandomBytes(42); + InputStream avatar0inputStream2 = + new ByteArrayInputStream(avatar0bytes2); + avatarManager0.addAvatar(contentType, avatar0inputStream2); + + // 0 now only sees their new avatar + header0 = avatarManager0.getMyAvatarHeader(); + assertNotNull(header0); + attachment0 = avatarManager0.getAvatar(header0); + assertStreamMatches(avatar0bytes2, attachment0.getStream()); + + // send the new avatar from 0 to 1 + sync0To1(1, true); + + // 1 only sees 0's new avatar + header0From1 = + avatarManager1.getAvatarHeader(contact0From1); + assertNotNull(header0From1); + attachment0From1 = avatarManager1.getAvatar(header0From1); + assertStreamMatches(avatar0bytes2, attachment0From1.getStream()); + } + + private void assertStreamMatches(byte[] bytes, InputStream inputStream) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + copyAndClose(inputStream, outputStream); + assertArrayEquals(bytes, outputStream.toByteArray()); + } + +} diff --git a/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarValidatorTest.java new file mode 100644 index 000000000..3d1bb8ece --- /dev/null +++ b/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarValidatorTest.java @@ -0,0 +1,188 @@ +package org.briarproject.briar.avatar; + +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.BdfReader; +import org.briarproject.bramble.api.data.BdfReaderFactory; +import org.briarproject.bramble.api.data.MetadataEncoder; +import org.briarproject.bramble.api.db.Metadata; +import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.InvalidMessageException; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageContext; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.test.BrambleMockTestCase; +import org.jmock.Expectations; +import org.junit.Test; + +import java.io.InputStream; + +import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; +import static org.briarproject.bramble.test.TestUtils.getClientId; +import static org.briarproject.bramble.test.TestUtils.getGroup; +import static org.briarproject.bramble.test.TestUtils.getMessage; +import static org.briarproject.bramble.util.StringUtils.getRandomString; +import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_BYTES; +import static org.briarproject.briar.avatar.AvatarConstants.MSG_KEY_VERSION; +import static org.briarproject.briar.avatar.AvatarConstants.MSG_TYPE_UPDATE; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_CONTENT_TYPE; +import static org.briarproject.briar.media.MediaConstants.MSG_KEY_DESCRIPTOR_LENGTH; +import static org.junit.Assert.assertEquals; + +public class AvatarValidatorTest extends BrambleMockTestCase { + + private final BdfReaderFactory bdfReaderFactory = + context.mock(BdfReaderFactory.class); + private final MetadataEncoder metadataEncoder = + context.mock(MetadataEncoder.class); + private final Clock clock = context.mock(Clock.class); + private final BdfReader reader = context.mock(BdfReader.class); + + private final Group group = getGroup(getClientId(), 123); + private final Message message = getMessage(group.getId()); + private final long now = message.getTimestamp() + 1000; + private final String contentType = getRandomString(MAX_CONTENT_TYPE_BYTES); + private final long version = System.currentTimeMillis(); + private final BdfDictionary meta = BdfDictionary.of( + new BdfEntry(MSG_KEY_VERSION, version), + new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType), + // Descriptor length is zero as the test doesn't read from the + // counting input stream + new BdfEntry(MSG_KEY_DESCRIPTOR_LENGTH, 0L) + ); + + private final AvatarValidator validator = + new AvatarValidator(bdfReaderFactory, metadataEncoder, clock); + + @Test(expected = InvalidMessageException.class) + public void testRejectsFarFutureTimestamp() throws Exception { + expectCheckTimestamp(message.getTimestamp() - MAX_CLOCK_DIFFERENCE - 1); + + validator.validateMessage(message, group); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsEmptyBody() throws Exception { + expectCheckTimestamp(now); + expectParseList(new BdfList()); + + validator.validateMessage(message, group); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsTooShortBody() throws Exception { + expectCheckTimestamp(now); + expectParseList(BdfList.of(MSG_TYPE_UPDATE, version)); + + validator.validateMessage(message, group); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsUnknownMessageType() throws Exception { + expectCheckTimestamp(now); + expectParseList(BdfList.of(MSG_TYPE_UPDATE + 1, version, contentType)); + + validator.validateMessage(message, group); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsNonLongVersion() throws Exception { + expectCheckTimestamp(now); + expectParseList(BdfList.of(MSG_TYPE_UPDATE, "foo", contentType)); + + validator.validateMessage(message, group); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsNonStringContentType() throws Exception { + expectCheckTimestamp(now); + expectParseList(BdfList.of(MSG_TYPE_UPDATE, version, 1337)); + + validator.validateMessage(message, group); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsEmptyContentType() throws Exception { + expectCheckTimestamp(now); + expectParseList(BdfList.of(MSG_TYPE_UPDATE, version, "")); + + validator.validateMessage(message, group); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsTooLongContentType() throws Exception { + String contentType = getRandomString(MAX_CONTENT_TYPE_BYTES + 1); + + expectCheckTimestamp(now); + expectParseList(BdfList.of(MSG_TYPE_UPDATE, version, contentType)); + + validator.validateMessage(message, group); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsTooLongBody() throws Exception { + expectCheckTimestamp(now); + expectParseList(BdfList.of(MSG_TYPE_UPDATE, version, contentType, 1)); + + validator.validateMessage(message, group); + } + + @Test(expected = InvalidMessageException.class) + public void testRejectsNegativeVersion() throws Exception { + expectCheckTimestamp(now); + expectParseList(BdfList.of(MSG_TYPE_UPDATE, -1, contentType)); + + validator.validateMessage(message, group); + } + + @Test + public void testAcceptsUpdateMessage() throws Exception { + testAcceptsUpdateMessage( + BdfList.of(MSG_TYPE_UPDATE, version, contentType), meta); + } + + @Test + public void testAcceptsZeroVersion() throws Exception { + BdfList body = BdfList.of(MSG_TYPE_UPDATE, 0L, contentType); + BdfDictionary meta = BdfDictionary.of( + new BdfEntry(MSG_KEY_VERSION, 0L), + new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType), + new BdfEntry(MSG_KEY_DESCRIPTOR_LENGTH, 0L) + ); + testAcceptsUpdateMessage(body, meta); + } + + private void testAcceptsUpdateMessage(BdfList body, BdfDictionary meta) + throws Exception { + expectCheckTimestamp(now); + expectParseList(body); + expectEncodeMetadata(meta); + + MessageContext result = validator.validateMessage(message, group); + assertEquals(0, result.getDependencies().size()); + } + + private void expectCheckTimestamp(long now) { + context.checking(new Expectations() {{ + oneOf(clock).currentTimeMillis(); + will(returnValue(now)); + }}); + } + + private void expectParseList(BdfList body) throws Exception { + context.checking(new Expectations() {{ + oneOf(bdfReaderFactory).createReader(with(any(InputStream.class))); + will(returnValue(reader)); + oneOf(reader).readList(); + will(returnValue(body)); + }}); + } + + private void expectEncodeMetadata(BdfDictionary meta) throws Exception { + context.checking(new Expectations() {{ + oneOf(metadataEncoder).encode(meta); + will(returnValue(new Metadata())); + }}); + } +} diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java index cb0051089..88b437e51 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java @@ -2,6 +2,7 @@ package org.briarproject.briar.introduction; import org.briarproject.bramble.BrambleCoreModule; import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule; +import org.briarproject.briar.avatar.AvatarModule; import org.briarproject.briar.blog.BlogModule; import org.briarproject.briar.client.BriarClientModule; import org.briarproject.briar.forum.ForumModule; @@ -19,6 +20,7 @@ import dagger.Component; @Component(modules = { BrambleCoreIntegrationTestModule.class, BrambleCoreModule.class, + AvatarModule.class, BlogModule.class, BriarClientModule.class, ForumModule.class, diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java index cc074a97a..8f5ea0526 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java @@ -12,6 +12,7 @@ import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.properties.TransportPropertyManager; import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule; +import org.briarproject.briar.api.avatar.AvatarManager; import org.briarproject.briar.api.blog.BlogFactory; import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.blog.BlogSharingManager; @@ -24,6 +25,7 @@ import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.PrivateMessageFactory; import org.briarproject.briar.api.privategroup.PrivateGroupManager; import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager; +import org.briarproject.briar.avatar.AvatarModule; import org.briarproject.briar.blog.BlogModule; import org.briarproject.briar.client.BriarClientModule; import org.briarproject.briar.forum.ForumModule; @@ -41,6 +43,7 @@ import dagger.Component; @Component(modules = { BrambleCoreIntegrationTestModule.class, BrambleCoreModule.class, + AvatarModule.class, BlogModule.class, BriarClientModule.class, ForumModule.class, @@ -55,6 +58,8 @@ public interface BriarIntegrationTestComponent void inject(BriarIntegrationTest init); + void inject(AvatarModule.EagerSingletons init); + void inject(BlogModule.EagerSingletons init); void inject(ForumModule.EagerSingletons init); @@ -75,6 +80,8 @@ public interface BriarIntegrationTestComponent IdentityManager getIdentityManager(); + AvatarManager getAvatarManager(); + ClientHelper getClientHelper(); ContactManager getContactManager(); @@ -117,6 +124,7 @@ public interface BriarIntegrationTestComponent BriarIntegrationTestComponent c) { BrambleCoreIntegrationTestEagerSingletons.Helper .injectEagerSingletons(c); + c.inject(new AvatarModule.EagerSingletons()); c.inject(new BlogModule.EagerSingletons()); c.inject(new ForumModule.EagerSingletons()); c.inject(new GroupInvitationModule.EagerSingletons()); From 100791c3f390430666a026bbf15b65588172ac33 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 23 Nov 2020 14:00:41 -0300 Subject: [PATCH 04/57] Don't accept incoming messages in our own avatar group --- .../briarproject/briar/avatar/AvatarManagerImpl.java | 5 +++++ .../briar/avatar/AvatarManagerImplTest.java | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarManagerImpl.java index 5e8818d14..5258458f4 100644 --- a/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarManagerImpl.java @@ -135,6 +135,11 @@ class AvatarManagerImpl implements AvatarManager, OpenDatabaseHook, ContactHook, @Override public boolean incomingMessage(Transaction txn, Message m, Metadata meta) throws DbException, InvalidMessageException { + Group ourGroup = getOurGroup(txn); + if (m.getGroupId().equals(ourGroup.getId())) { + throw new InvalidMessageException( + "Received incoming message in my avatar group"); + } try { // Find the latest update, if any BdfDictionary d = metadataParser.parse(meta); diff --git a/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java index b83c063a1..9a0436634 100644 --- a/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java @@ -180,6 +180,7 @@ public class AvatarManagerImplTest extends BrambleMockTestCase { new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType) ); + expectGetOurGroup(txn); context.checking(new Expectations() {{ oneOf(metadataParser).parse(meta); will(returnValue(d)); @@ -211,6 +212,7 @@ public class AvatarManagerImplTest extends BrambleMockTestCase { new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType) ); + expectGetOurGroup(txn); context.checking(new Expectations() {{ oneOf(metadataParser).parse(meta); will(returnValue(d)); @@ -241,6 +243,7 @@ public class AvatarManagerImplTest extends BrambleMockTestCase { new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType) ); + expectGetOurGroup(txn); context.checking(new Expectations() {{ oneOf(metadataParser).parse(meta); will(returnValue(d)); @@ -256,6 +259,14 @@ public class AvatarManagerImplTest extends BrambleMockTestCase { assertEquals(0, txn.getActions().size()); } + @Test(expected = InvalidMessageException.class) + public void testIncomingMessageInOwnGroup() + throws DbException, InvalidMessageException, FormatException { + Transaction txn = new Transaction(null, false); + expectGetOurGroup(txn); + avatarManager.incomingMessage(txn, ourMsg, meta); + } + @Test public void testAddAvatar() throws Exception { byte[] avatarBytes = getRandomBytes(42); From ec972e8a1d056799bfc07b90f9f5622e7f13aebe Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 23 Nov 2020 14:26:16 -0300 Subject: [PATCH 05/57] Handle concurrent updates of our avatar --- .../briar/avatar/AvatarManagerImpl.java | 24 ++++++----- .../briar/avatar/AvatarManagerImplTest.java | 40 ++++++++++++++++++- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarManagerImpl.java index 5258458f4..c69c3390f 100644 --- a/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarManagerImpl.java @@ -175,8 +175,6 @@ class AvatarManagerImpl implements AvatarManager, OpenDatabaseHook, ContactHook, Transaction txn = db.startTransaction(true); try { groupId = getOurGroup(txn).getId(); - // TODO this might not be the latest anymore at the end of this method - // Can we run everything in one transaction? Probably not. latest = findLatest(txn, groupId); db.commitTransaction(txn); } finally { @@ -184,7 +182,6 @@ class AvatarManagerImpl implements AvatarManager, OpenDatabaseHook, ContactHook, } long version = latest == null ? 0 : latest.version + 1; // 0.0: Message Type, Version, Content-Type - // TODO do we need to add the message type explicitly? BdfList list = BdfList.of(MSG_TYPE_UPDATE, version, contentType); byte[] descriptor = clientHelper.toByteArray(list); // add BdfList and stream content to body @@ -202,16 +199,23 @@ class AvatarManagerImpl implements AvatarManager, OpenDatabaseHook, ContactHook, meta.put(MSG_KEY_VERSION, version); meta.put(MSG_KEY_CONTENT_TYPE, contentType); meta.put(MSG_KEY_DESCRIPTOR_LENGTH, descriptor.length); - // send message - db.transaction(false, txn2 -> { - if (latest != null) { - // delete previous update - db.deleteMessage(txn2, latest.messageId); - db.deleteMessageMetadata(txn2, latest.messageId); + // save/send avatar and delete old one + return db.transactionWithResult(false, txn2 -> { + // re-query latest update as it might have changed since last query + LatestUpdate newLatest = findLatest(txn2, groupId); + if (newLatest != null && newLatest.version > version) { + // latest update is newer than our own + // no need to store or delete anything, just return latest + return new AttachmentHeader(newLatest.messageId, + newLatest.contentType); + } else if (newLatest != null) { + // delete latest update if it has the same or lower version + db.deleteMessage(txn2, newLatest.messageId); + db.deleteMessageMetadata(txn2, newLatest.messageId); } clientHelper.addLocalMessage(txn2, m, meta, true, false); + return new AttachmentHeader(m.getId(), contentType); }); - return new AttachmentHeader(m.getId(), contentType); } @Nullable diff --git a/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java index 9a0436634..53168f763 100644 --- a/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java @@ -294,7 +294,7 @@ public class AvatarManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).createMessage(with(equal(localGroupId)), with(equal(now)), with(any(byte[].class))); will(returnValue(newMsg)); - oneOf(db).transaction(with(false), withDbRunnable(txn2)); + oneOf(db).transactionWithResult(with(false), withDbCallable(txn2)); oneOf(db).deleteMessage(txn2, ourMsg.getId()); oneOf(db).deleteMessageMetadata(txn2, ourMsg.getId()); oneOf(clientHelper) @@ -302,6 +302,7 @@ public class AvatarManagerImplTest extends BrambleMockTestCase { }}); expectGetOurGroup(txn); expectFindLatest(txn, localGroupId, ourMsg.getId(), metaDict); + expectFindLatest(txn2, localGroupId, ourMsg.getId(), metaDict); AttachmentHeader header = avatarManager.addAvatar(contentType, inputStream); @@ -309,6 +310,43 @@ public class AvatarManagerImplTest extends BrambleMockTestCase { assertEquals(contentType, header.getContentType()); } + @Test + public void testAddAvatarConcurrently() throws Exception { + byte[] avatarBytes = getRandomBytes(42); + InputStream inputStream = new ByteArrayInputStream(avatarBytes); + Transaction txn = new Transaction(null, true); + Transaction txn2 = new Transaction(null, false); + long latestVersion = metaDict.getLong(MSG_KEY_VERSION); + Message newMsg = getMessage(localGroupId); + BdfDictionary newMeta = BdfDictionary.of( + new BdfEntry(MSG_KEY_VERSION, latestVersion + 2), + new BdfEntry(MSG_KEY_CONTENT_TYPE, contentType), + new BdfEntry(MSG_KEY_DESCRIPTOR_LENGTH, 0) + ); + context.checking(new DbExpectations() {{ + oneOf(db).startTransaction(true); + will(returnValue(txn)); + oneOf(db).commitTransaction(txn); + oneOf(db).endTransaction(txn); + oneOf(clientHelper).toByteArray(with(any(BdfList.class))); + oneOf(clock).currentTimeMillis(); + oneOf(clientHelper).createMessage(with(equal(localGroupId)), + with(any(long.class)), with(any(byte[].class))); + will(returnValue(newMsg)); + oneOf(db).transactionWithResult(with(false), withDbCallable(txn2)); + // no deletion or storing happening + }}); + expectGetOurGroup(txn); + expectFindLatest(txn, localGroupId, ourMsg.getId(), metaDict); + // second query for latest update returns higher version + expectFindLatest(txn2, localGroupId, ourMsg.getId(), newMeta); + + AttachmentHeader header = + avatarManager.addAvatar(contentType, inputStream); + assertEquals(ourMsg.getId(), header.getMessageId()); + assertEquals(contentType, header.getContentType()); + } + private void expectGetContactId(Transaction txn, GroupId groupId, ContactId contactId) throws DbException, FormatException { BdfDictionary d = BdfDictionary From 8b45e01c426562c0af7b14229b2213a980598d2b Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 23 Nov 2020 14:35:38 -0300 Subject: [PATCH 06/57] Split up AvatarManagerImplTests --- .../briar/avatar/AvatarModule.java | 6 +-- .../briar/avatar/AvatarManagerImplTest.java | 44 +++++++++++-------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarModule.java b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarModule.java index 446e21437..cfc9807e4 100644 --- a/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarModule.java +++ b/briar-core/src/main/java/org/briarproject/briar/avatar/AvatarModule.java @@ -34,11 +34,11 @@ public class AvatarModule { AvatarValidator provideAvatarValidator(ValidationManager validationManager, BdfReaderFactory bdfReaderFactory, MetadataEncoder metadataEncoder, Clock clock) { - AvatarValidator introductionValidator = + AvatarValidator avatarValidator = new AvatarValidator(bdfReaderFactory, metadataEncoder, clock); validationManager.registerMessageValidator(CLIENT_ID, MAJOR_VERSION, - introductionValidator); - return introductionValidator; + avatarValidator); + return avatarValidator; } @Provides diff --git a/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java index 53168f763..eecff7506 100644 --- a/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/avatar/AvatarManagerImplTest.java @@ -96,7 +96,8 @@ public class AvatarManagerImplTest extends BrambleMockTestCase { clock); @Test - public void testOpenDatabaseHook() throws DbException, FormatException { + public void testOpenDatabaseHookWhenGroupExists() + throws DbException, FormatException { Transaction txn = new Transaction(null, false); // local group already exists, so nothing more to do @@ -108,6 +109,11 @@ public class AvatarManagerImplTest extends BrambleMockTestCase { will(returnValue(true)); }}); avatarManager.onDatabaseOpened(txn); + } + + @Test + public void testOpenDatabaseHook() throws DbException, FormatException { + Transaction txn = new Transaction(null, false); // local group does not exist, so we need to set things up for contacts expectCreateGroup(localAuthor.getId(), localGroup); @@ -149,27 +155,29 @@ public class AvatarManagerImplTest extends BrambleMockTestCase { } @Test - public void testOnClientVisibilityChanging() throws DbException { + public void testOnClientVisibilityChangingVisible() throws DbException { + testOnClientVisibilityChanging(VISIBLE); + } + + @Test + public void testOnClientVisibilityChangingShared() throws DbException { + testOnClientVisibilityChanging(SHARED); + } + + @Test + public void testOnClientVisibilityChangingInvisible() throws DbException { + testOnClientVisibilityChanging(INVISIBLE); + } + + private void testOnClientVisibilityChanging(Visibility v) + throws DbException { Transaction txn = new Transaction(null, false); expectGetOurGroup(txn); expectCreateGroup(contact.getAuthor().getId(), contactGroup); - expectSetGroupVisibility(txn, contact.getId(), localGroupId, VISIBLE); - expectSetGroupVisibility(txn, contact.getId(), contactGroupId, VISIBLE); - avatarManager.onClientVisibilityChanging(txn, contact, VISIBLE); - - expectGetOurGroup(txn); - expectCreateGroup(contact.getAuthor().getId(), contactGroup); - expectSetGroupVisibility(txn, contact.getId(), localGroupId, SHARED); - expectSetGroupVisibility(txn, contact.getId(), contactGroupId, SHARED); - avatarManager.onClientVisibilityChanging(txn, contact, SHARED); - - expectGetOurGroup(txn); - expectCreateGroup(contact.getAuthor().getId(), contactGroup); - expectSetGroupVisibility(txn, contact.getId(), localGroupId, INVISIBLE); - expectSetGroupVisibility(txn, contact.getId(), contactGroupId, - INVISIBLE); - avatarManager.onClientVisibilityChanging(txn, contact, INVISIBLE); + expectSetGroupVisibility(txn, contact.getId(), localGroupId, v); + expectSetGroupVisibility(txn, contact.getId(), contactGroupId, v); + avatarManager.onClientVisibilityChanging(txn, contact, v); } @Test From cf8f5c989f69574d596628a449c80f5a50435ed3 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 24 Nov 2020 09:36:10 -0300 Subject: [PATCH 07/57] Move AuthorInfo from bramble to briar --- .idea/runConfigurations/All_tests.xml | 1 + .../All_tests_in_briar_api.xml | 14 +++ .../bramble/api/contact/ContactManager.java | 11 -- .../bramble/contact/ContactManagerImpl.java | 25 ---- .../contact/ContactManagerImplTest.java | 77 ------------ .../briar/android/AndroidComponent.java | 3 + .../briar/android/blog/BlogPostItem.java | 2 +- .../briar/android/forum/ForumPostItem.java | 2 +- .../conversation/GroupMessageItem.java | 2 +- .../JoinMessageItemViewHolder.java | 2 +- .../android/privategroup/list/GroupItem.java | 2 +- .../privategroup/list/GroupListViewModel.java | 11 +- .../memberlist/MemberListItem.java | 4 +- .../memberlist/MemberListItemHolder.java | 2 +- .../briar/android/threaded/ThreadItem.java | 2 +- .../briar/android/view/AuthorView.java | 6 +- .../android/view/TrustIndicatorView.java | 2 +- .../android/forum/ForumActivityTest.java | 4 +- .../list/GroupListViewModelTest.java | 12 +- briar-api/build.gradle | 3 + .../briar/api/blog/BlogCommentHeader.java | 2 +- .../briar/api/blog/BlogPostHeader.java | 2 +- .../briar/api/client/PostHeader.java | 4 +- .../briar/api/forum/ForumPostHeader.java | 2 +- .../briar}/api/identity/AuthorInfo.java | 3 +- .../briar/api/identity/AuthorManager.java | 21 ++++ .../api/introduction/IntroductionRequest.java | 2 +- .../introduction/IntroductionResponse.java | 2 +- .../briar/api/privategroup/GroupMember.java | 2 +- .../api/privategroup/GroupMessageHeader.java | 2 +- .../briar}/api/identity/AuthorInfoTest.java | 6 +- .../briar/BriarCoreEagerSingletons.java | 4 + .../briarproject/briar/BriarCoreModule.java | 2 + .../briar/blog/BlogManagerImpl.java | 18 +-- .../briar/forum/ForumManagerImpl.java | 18 +-- .../briar/identity/AuthorManagerImpl.java | 56 +++++++++ .../briar/identity/IdentityModule.java | 25 ++++ .../introduction/AbstractProtocolEngine.java | 8 +- .../IntroduceeProtocolEngine.java | 12 +- .../IntroducerProtocolEngine.java | 6 +- .../introduction/IntroductionManagerImpl.java | 12 +- .../privategroup/PrivateGroupManagerImpl.java | 21 ++-- .../briar/blog/BlogManagerImplTest.java | 34 +++--- .../blog/BlogManagerIntegrationTest.java | 2 +- .../FeedManagerIntegrationTestComponent.java | 2 + .../briar/identity/AuthorManagerImplTest.java | 115 ++++++++++++++++++ .../IntroductionIntegrationTestComponent.java | 2 + .../MessageSizeIntegrationTestComponent.java | 2 + .../PrivateGroupIntegrationTest.java | 2 +- .../PrivateGroupManagerIntegrationTest.java | 2 +- .../test/BriarIntegrationTestComponent.java | 5 + .../bramble/identity/OutputAuthor.kt | 2 +- .../headless/blogs/BlogControllerTest.kt | 4 +- .../headless/event/WebSocketControllerTest.kt | 4 +- .../messaging/MessagingControllerImplTest.kt | 6 +- 55 files changed, 378 insertions(+), 221 deletions(-) create mode 100644 .idea/runConfigurations/All_tests_in_briar_api.xml rename {bramble-api/src/main/java/org/briarproject/bramble => briar-api/src/main/java/org/briarproject/briar}/api/identity/AuthorInfo.java (92%) create mode 100644 briar-api/src/main/java/org/briarproject/briar/api/identity/AuthorManager.java rename {bramble-api/src/test/java/org/briarproject/bramble => briar-api/src/test/java/org/briarproject/briar}/api/identity/AuthorInfoTest.java (79%) create mode 100644 briar-core/src/main/java/org/briarproject/briar/identity/AuthorManagerImpl.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/identity/IdentityModule.java create mode 100644 briar-core/src/test/java/org/briarproject/briar/identity/AuthorManagerImplTest.java diff --git a/.idea/runConfigurations/All_tests.xml b/.idea/runConfigurations/All_tests.xml index 7d53e9dcc..b06a2885f 100644 --- a/.idea/runConfigurations/All_tests.xml +++ b/.idea/runConfigurations/All_tests.xml @@ -13,6 +13,7 @@