diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTest.java b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTest.java index 1714a49ea9b6861671d83be2e1313cbbe423262c..a9e21a6b0f9364938fad3bc829a0b918f877e824 100644 --- a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTest.java +++ b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTest.java @@ -31,6 +31,7 @@ import org.briarproject.crypto.CryptoModule; import org.briarproject.forum.ForumModule; import org.briarproject.lifecycle.LifecycleModule; import org.briarproject.properties.PropertiesModule; +import org.briarproject.sharing.SharingModule; import org.briarproject.sync.SyncModule; import org.briarproject.transport.TransportModule; import org.briarproject.util.StringUtils; @@ -188,7 +189,7 @@ public class ForumManagerTest { // share forum GroupId g = forum0.getId(); - forumSharingManager0.sendForumInvitation(g, contactId1, null); + forumSharingManager0.sendInvitation(g, contactId1, null); sync0To1(); deliveryWaiter.await(TIMEOUT, 1); Contact c0 = contactManager1.getContact(contactId0); @@ -218,7 +219,7 @@ public class ForumManagerTest { // share forum GroupId g = forum0.getId(); - forumSharingManager0.sendForumInvitation(g, contactId1, null); + forumSharingManager0.sendInvitation(g, contactId1, null); sync0To1(); deliveryWaiter.await(TIMEOUT, 1); Contact c0 = contactManager1.getContact(contactId0); @@ -259,7 +260,7 @@ public class ForumManagerTest { // share forum GroupId g = forum0.getId(); - forumSharingManager0.sendForumInvitation(g, contactId1, null); + forumSharingManager0.sendInvitation(g, contactId1, null); sync0To1(); deliveryWaiter.await(TIMEOUT, 1); Contact c0 = contactManager1.getContact(contactId0); @@ -270,7 +271,7 @@ public class ForumManagerTest { // share a second forum Forum forum1 = forumManager0.addForum("Test Forum1"); GroupId g1 = forum1.getId(); - forumSharingManager0.sendForumInvitation(g1, contactId1, null); + forumSharingManager0.sendInvitation(g1, contactId1, null); sync0To1(); deliveryWaiter.await(TIMEOUT, 1); forumSharingManager1.respondToInvitation(forum1, c0, true); @@ -426,6 +427,7 @@ public class ForumManagerTest { component.inject(new CryptoModule.EagerSingletons()); component.inject(new ContactModule.EagerSingletons()); component.inject(new TransportModule.EagerSingletons()); + component.inject(new SharingModule.EagerSingletons()); component.inject(new SyncModule.EagerSingletons()); component.inject(new PropertiesModule.EagerSingletons()); } diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java index 8a9e5fc6db41a653e6e9737a39874cb89dce6b4c..7e74d841b01a425caec7deac4ce9235d3c77767a 100644 --- a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java +++ b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java @@ -17,6 +17,7 @@ import org.briarproject.forum.ForumModule; import org.briarproject.identity.IdentityModule; import org.briarproject.lifecycle.LifecycleModule; import org.briarproject.properties.PropertiesModule; +import org.briarproject.sharing.SharingModule; import org.briarproject.sync.SyncModule; import org.briarproject.system.SystemModule; import org.briarproject.transport.TransportModule; @@ -40,6 +41,7 @@ import dagger.Component; IdentityModule.class, LifecycleModule.class, PropertiesModule.class, + SharingModule.class, SyncModule.class, SystemModule.class, TransportModule.class @@ -58,6 +60,8 @@ public interface ForumManagerTestComponent { void inject(PropertiesModule.EagerSingletons init); + void inject(SharingModule.EagerSingletons init); + void inject(SyncModule.EagerSingletons init); void inject(TransportModule.EagerSingletons init); diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java index 3d55604e30852e8986f33c80d1c0d2532dcf9b4a..522ca424ee2d26af423b0a5743f348d5e98380ec 100644 --- a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java +++ b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java @@ -39,6 +39,7 @@ import org.briarproject.crypto.CryptoModule; import org.briarproject.forum.ForumModule; import org.briarproject.lifecycle.LifecycleModule; import org.briarproject.properties.PropertiesModule; +import org.briarproject.sharing.SharingModule; import org.briarproject.sync.SyncModule; import org.briarproject.transport.TransportModule; import org.junit.After; @@ -61,8 +62,8 @@ import javax.inject.Inject; import static org.briarproject.TestPluginsModule.MAX_LATENCY; import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_INVITATION; import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; import static org.briarproject.api.sync.ValidationManager.State.DELIVERED; import static org.briarproject.api.sync.ValidationManager.State.INVALID; import static org.junit.Assert.assertEquals; @@ -159,7 +160,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // send invitation forumSharingManager0 - .sendForumInvitation(forum0.getId(), contactId1, "Hi!"); + .sendInvitation(forum0.getId(), contactId1, "Hi!"); // sync first request message syncToInvitee(); @@ -172,13 +173,13 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(listener0.responseReceived); // forum was added successfully - assertEquals(0, forumSharingManager0.getAvailableForums().size()); + assertEquals(0, forumSharingManager0.getAvailable().size()); assertEquals(1, forumManager1.getForums().size()); // invitee has one invitation message from sharer List<ForumInvitationMessage> list = new ArrayList<>(forumSharingManager1 - .getForumInvitationMessages(contactId0)); + .getInvitationMessages(contactId0)); assertEquals(1, list.size()); // check other things are alright with the forum message ForumInvitationMessage invitation = list.get(0); @@ -188,7 +189,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertEquals("Hi!", invitation.getMessage()); // sharer has own invitation message assertEquals(1, - forumSharingManager0.getForumInvitationMessages(contactId1) + forumSharingManager0.getInvitationMessages(contactId1) .size()); // forum can not be shared again Contact c1 = contactManager0.getContact(contactId1); @@ -209,7 +210,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // send invitation forumSharingManager0 - .sendForumInvitation(forum0.getId(), contactId1, null); + .sendInvitation(forum0.getId(), contactId1, null); // sync first request message syncToInvitee(); @@ -222,15 +223,15 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(listener0.responseReceived); // forum was not added - assertEquals(0, forumSharingManager0.getAvailableForums().size()); + assertEquals(0, forumSharingManager0.getAvailable().size()); assertEquals(0, forumManager1.getForums().size()); // forum is no longer available to invitee who declined - assertEquals(0, forumSharingManager1.getAvailableForums().size()); + assertEquals(0, forumSharingManager1.getAvailable().size()); // invitee has one invitation message from sharer List<ForumInvitationMessage> list = new ArrayList<>(forumSharingManager1 - .getForumInvitationMessages(contactId0)); + .getInvitationMessages(contactId0)); assertEquals(1, list.size()); // check other things are alright with the forum message ForumInvitationMessage invitation = list.get(0); @@ -240,7 +241,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertEquals(null, invitation.getMessage()); // sharer has own invitation message assertEquals(1, - forumSharingManager0.getForumInvitationMessages(contactId1) + forumSharingManager0.getInvitationMessages(contactId1) .size()); // forum can be shared again Contact c1 = contactManager0.getContact(contactId1); @@ -259,7 +260,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // send invitation forumSharingManager0 - .sendForumInvitation(forum0.getId(), contactId1, "Hi!"); + .sendInvitation(forum0.getId(), contactId1, "Hi!"); // sync first request message syncToInvitee(); @@ -272,7 +273,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(listener0.responseReceived); // forum was added successfully - assertEquals(0, forumSharingManager0.getAvailableForums().size()); + assertEquals(0, forumSharingManager0.getAvailable().size()); assertEquals(1, forumManager1.getForums().size()); assertTrue(forumManager1.getForums().contains(forum0)); @@ -292,7 +293,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { syncToSharer(); // forum is gone - assertEquals(0, forumSharingManager0.getAvailableForums().size()); + assertEquals(0, forumSharingManager0.getAvailable().size()); assertEquals(0, forumManager1.getForums().size()); // sharer no longer shares forum with invitee @@ -319,7 +320,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // send invitation forumSharingManager0 - .sendForumInvitation(forum0.getId(), contactId1, null); + .sendInvitation(forum0.getId(), contactId1, null); // sync first request message syncToInvitee(); @@ -332,7 +333,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(listener0.responseReceived); // forum was added successfully - assertEquals(0, forumSharingManager0.getAvailableForums().size()); + assertEquals(0, forumSharingManager0.getAvailable().size()); assertEquals(1, forumManager1.getForums().size()); assertTrue(forumManager1.getForums().contains(forum0)); @@ -378,7 +379,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // send invitation forumSharingManager0 - .sendForumInvitation(forum0.getId(), contactId1, null); + .sendInvitation(forum0.getId(), contactId1, null); // sharer un-subscribes from forum forumManager0.removeForum(forum0); @@ -392,7 +393,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(listener1.requestReceived); // invitee has no forums available - assertEquals(0, forumSharingManager1.getAvailableForums().size()); + assertEquals(0, forumSharingManager1.getAvailable().size()); } finally { stopLifecycles(); } @@ -407,7 +408,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // send invitation forumSharingManager0 - .sendForumInvitation(forum0.getId(), contactId1, "Hi!"); + .sendInvitation(forum0.getId(), contactId1, "Hi!"); // sync first request message syncToInvitee(); @@ -428,7 +429,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // get SessionId from invitation List<ForumInvitationMessage> list = new ArrayList<>( forumSharingManager1 - .getForumInvitationMessages(contactId0)); + .getInvitationMessages(contactId0)); assertEquals(1, list.size()); ForumInvitationMessage msg = list.get(0); SessionId sessionId = msg.getSessionId(); @@ -475,7 +476,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // send invitation forumSharingManager0 - .sendForumInvitation(forum0.getId(), contactId1, "Hi!"); + .sendInvitation(forum0.getId(), contactId1, "Hi!"); // sync first request message syncToInvitee(); @@ -491,7 +492,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertEquals(1, forumManager1.getForums().size()); // invitee now shares same forum back - forumSharingManager1.sendForumInvitation(forum0.getId(), + forumSharingManager1.sendInvitation(forum0.getId(), contactId0, "I am re-sharing this forum with you."); @@ -501,7 +502,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // make sure that no new request was received assertFalse(listener0.requestReceived); assertEquals(1, - forumSharingManager0.getForumInvitationMessages(contactId1) + forumSharingManager0.getInvitationMessages(contactId1) .size()); } finally { stopLifecycles(); @@ -524,10 +525,10 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // send invitation forumSharingManager0 - .sendForumInvitation(forum0.getId(), contactId1, "Hi!"); + .sendInvitation(forum0.getId(), contactId1, "Hi!"); // invitee now shares same forum back - forumSharingManager1.sendForumInvitation(forum0.getId(), + forumSharingManager1.sendInvitation(forum0.getId(), contactId0, "I am re-sharing this forum with you."); // find out who should be Alice, because of random keys @@ -555,9 +556,9 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(listener0.responseReceived); assertEquals(1, forumSharingManager0 - .getForumInvitationMessages(contactId1).size()); + .getInvitationMessages(contactId1).size()); assertEquals(2, forumSharingManager1 - .getForumInvitationMessages(contactId0).size()); + .getInvitationMessages(contactId0).size()); } else { eventWaiter.await(TIMEOUT, 1); assertTrue(listener0.requestReceived); @@ -568,9 +569,9 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(listener1.responseReceived); assertEquals(2, forumSharingManager0 - .getForumInvitationMessages(contactId1).size()); + .getInvitationMessages(contactId1).size()); assertEquals(1, forumSharingManager1 - .getForumInvitationMessages(contactId0).size()); + .getInvitationMessages(contactId0).size()); } } finally { stopLifecycles(); @@ -586,7 +587,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // send invitation forumSharingManager0 - .sendForumInvitation(forum0.getId(), contactId1, "Hi!"); + .sendInvitation(forum0.getId(), contactId1, "Hi!"); // sync first request message syncToInvitee(); @@ -606,7 +607,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // remember SessionId from invitation List<ForumInvitationMessage> list = new ArrayList<>( forumSharingManager1 - .getForumInvitationMessages(contactId0)); + .getInvitationMessages(contactId0)); assertEquals(1, list.size()); ForumInvitationMessage msg = list.get(0); SessionId sessionId = msg.getSessionId(); @@ -687,20 +688,20 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // send invitation forumSharingManager0 - .sendForumInvitation(forum0.getId(), contactId1, "Hi!"); + .sendInvitation(forum0.getId(), contactId1, "Hi!"); // sync first request message syncToInvitee(); // second sharer sends invitation for same forum forumSharingManager2 - .sendForumInvitation(forum0.getId(), contactId1, null); + .sendInvitation(forum0.getId(), contactId1, null); // sync second request message deliverMessage(sync2, contactId2, sync1, contactId1, "Sharer2 to Invitee"); // make sure we have only one forum available Collection<Forum> forums = - forumSharingManager1.getAvailableForums(); + forumSharingManager1.getAvailable(); assertEquals(1, forums.size()); // make sure both sharers actually share the forum @@ -958,6 +959,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { component.inject(new CryptoModule.EagerSingletons()); component.inject(new ContactModule.EagerSingletons()); component.inject(new TransportModule.EagerSingletons()); + component.inject(new SharingModule.EagerSingletons()); component.inject(new SyncModule.EagerSingletons()); component.inject(new PropertiesModule.EagerSingletons()); } diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTestComponent.java b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTestComponent.java index 55f3d8de82b117a6b2d415f03458c70210a8aa75..8e3ecdf9f6b5ce55cf19f5ef51a135f65bda6eea 100644 --- a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTestComponent.java +++ b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTestComponent.java @@ -21,6 +21,7 @@ import org.briarproject.forum.ForumModule; import org.briarproject.identity.IdentityModule; import org.briarproject.lifecycle.LifecycleModule; import org.briarproject.properties.PropertiesModule; +import org.briarproject.sharing.SharingModule; import org.briarproject.sync.SyncModule; import org.briarproject.system.SystemModule; import org.briarproject.transport.TransportModule; @@ -44,6 +45,7 @@ import dagger.Component; IdentityModule.class, LifecycleModule.class, PropertiesModule.class, + SharingModule.class, SyncModule.class, SystemModule.class, TransportModule.class @@ -62,6 +64,8 @@ public interface ForumSharingIntegrationTestComponent { void inject(PropertiesModule.EagerSingletons init); + void inject(SharingModule.EagerSingletons init); + void inject(SyncModule.EagerSingletons init); void inject(TransportModule.EagerSingletons init); diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java index d0514a17229dc5458b675b6eeb5172a8b3387f32..7b71d84f040b0086010ce833d0d38a082d422a83 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java @@ -352,7 +352,7 @@ public class ContactListFragment extends BaseFragment implements EventListener { now = System.currentTimeMillis(); Collection<ForumInvitationMessage> invitations = - forumSharingManager.getForumInvitationMessages(id); + forumSharingManager.getInvitationMessages(id); for (ForumInvitationMessage i : invitations) { messages.add(ConversationItem.from(i)); } diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java index b1507615aedf709d828438b94a05ab584553592c..116d2a6354b6a3c18f297926f707487552c5d386 100644 --- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java +++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java @@ -316,7 +316,7 @@ public class ConversationActivity extends BriarActivity .getIntroductionMessages(contactId); Collection<ForumInvitationMessage> invitations = forumSharingManager - .getForumInvitationMessages(contactId); + .getInvitationMessages(contactId); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Loading headers took " + duration + " ms"); diff --git a/briar-android/src/org/briarproject/android/forum/AvailableForumsActivity.java b/briar-android/src/org/briarproject/android/forum/AvailableForumsActivity.java index 15e919c90283e040dbb0825a7120a4af9999080c..f7034475cfe2b89f043f887a0a3f11030d8a714f 100644 --- a/briar-android/src/org/briarproject/android/forum/AvailableForumsActivity.java +++ b/briar-android/src/org/briarproject/android/forum/AvailableForumsActivity.java @@ -82,7 +82,7 @@ public class AvailableForumsActivity extends BriarActivity try { Collection<ForumContacts> available = new ArrayList<>(); long now = System.currentTimeMillis(); - for (Forum f : forumSharingManager.getAvailableForums()) { + for (Forum f : forumSharingManager.getAvailable()) { try { Collection<Contact> c = forumSharingManager.getSharedBy(f.getId()); diff --git a/briar-android/src/org/briarproject/android/forum/ContactSelectorFragment.java b/briar-android/src/org/briarproject/android/forum/ContactSelectorFragment.java index 8cefe834f75e42d1b7f107b4f052c1054301a0c2..313231ebcbdbc8f74aabae4d41ac4191e9b2f61d 100644 --- a/briar-android/src/org/briarproject/android/forum/ContactSelectorFragment.java +++ b/briar-android/src/org/briarproject/android/forum/ContactSelectorFragment.java @@ -38,7 +38,7 @@ import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static org.briarproject.android.forum.ShareForumActivity.CONTACTS; import static org.briarproject.android.forum.ShareForumActivity.getContactsFromIds; -import static org.briarproject.api.forum.ForumConstants.GROUP_ID; +import static org.briarproject.api.sharing.SharingConstants.GROUP_ID; public class ContactSelectorFragment extends BaseFragment implements BaseContactListAdapter.OnItemClickListener { diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java index afe61864a7e6cd7b725ad9e4ad395f81dbde2f04..ea33d2b3791ef52c646f3dec39acbef7929a679f 100644 --- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java +++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java @@ -177,7 +177,7 @@ public class ForumListFragment extends BaseEventFragment implements try { long now = System.currentTimeMillis(); int available = - forumSharingManager.getAvailableForums().size(); + forumSharingManager.getAvailable().size(); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) LOG.info("Loading available took " + duration + " ms"); diff --git a/briar-android/src/org/briarproject/android/forum/ShareForumMessageFragment.java b/briar-android/src/org/briarproject/android/forum/ShareForumMessageFragment.java index d88c33d548a6a2bf67bc874e8266fc1840a0596d..cf2b6e16062c4ffb5990fe27b6d0baa28e5f1afa 100644 --- a/briar-android/src/org/briarproject/android/forum/ShareForumMessageFragment.java +++ b/briar-android/src/org/briarproject/android/forum/ShareForumMessageFragment.java @@ -28,7 +28,7 @@ import static android.widget.Toast.LENGTH_SHORT; import static java.util.logging.Level.WARNING; import static org.briarproject.android.forum.ShareForumActivity.CONTACTS; import static org.briarproject.android.forum.ShareForumActivity.getContactsFromIds; -import static org.briarproject.api.forum.ForumConstants.GROUP_ID; +import static org.briarproject.api.sharing.SharingConstants.GROUP_ID; public class ShareForumMessageFragment extends BaseFragment { @@ -136,7 +136,7 @@ public class ShareForumMessageFragment extends BaseFragment { public void run() { try { for (ContactId c : contacts) { - forumSharingManager.sendForumInvitation(groupId, c, + forumSharingManager.sendInvitation(groupId, c, msg); } } catch (DbException e) { diff --git a/briar-api/src/org/briarproject/api/blogs/BlogConstants.java b/briar-api/src/org/briarproject/api/blogs/BlogConstants.java index 60f06a641b5591ed79c35d32e785d3265358cff6..738e012a3ef2872f1c341aacc7e5a6a68d5a7da5 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogConstants.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogConstants.java @@ -22,6 +22,12 @@ public interface BlogConstants { /** The maximum length of a blog post's body in bytes. */ int MAX_BLOG_POST_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024; + /* Blog Sharing Constants */ + String BLOG_TITLE = "blogTitle"; + String BLOG_DESC = "blogDescription"; + String BLOG_AUTHOR_NAME = "blogAuthorName"; + String BLOG_PUBLIC_KEY = "blogPublicKey"; + // Metadata keys String KEY_DESCRIPTION = "description"; String KEY_TITLE = "title"; diff --git a/briar-api/src/org/briarproject/api/blogs/BlogInvitationMessage.java b/briar-api/src/org/briarproject/api/blogs/BlogInvitationMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..9306da5726c5a74cea45a1524f573949c6f686df --- /dev/null +++ b/briar-api/src/org/briarproject/api/blogs/BlogInvitationMessage.java @@ -0,0 +1,26 @@ +package org.briarproject.api.blogs; + +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.sharing.InvitationMessage; +import org.briarproject.api.sync.MessageId; + +public class BlogInvitationMessage extends InvitationMessage { + + private final String blogTitle; + + public BlogInvitationMessage(MessageId id, SessionId sessionId, + ContactId contactId, String blogTitle, String message, + boolean available, long time, boolean local, boolean sent, + boolean seen, boolean read) { + + super(id, sessionId, contactId, message, available, time, local, sent, + seen, read); + this.blogTitle = blogTitle; + } + + public String getBlogTitle() { + return blogTitle; + } + +} diff --git a/briar-api/src/org/briarproject/api/blogs/BlogSharingManager.java b/briar-api/src/org/briarproject/api/blogs/BlogSharingManager.java new file mode 100644 index 0000000000000000000000000000000000000000..ec9f23e49df4910fc2bdc5935fd98b4e9eed4cbd --- /dev/null +++ b/briar-api/src/org/briarproject/api/blogs/BlogSharingManager.java @@ -0,0 +1,60 @@ +package org.briarproject.api.blogs; + +import org.briarproject.api.contact.Contact; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.db.DbException; +import org.briarproject.api.sharing.SharingManager; +import org.briarproject.api.sync.ClientId; +import org.briarproject.api.sync.GroupId; + +import java.util.Collection; + +public interface BlogSharingManager + extends SharingManager<Blog, BlogInvitationMessage> { + + /** + * Returns the unique ID of the blog sharing client. + */ + ClientId getClientId(); + + /** + * Sends an invitation to share the given blog with the given contact + * and sends an optional message along with it. + */ + void sendInvitation(GroupId groupId, ContactId contactId, + String message) throws DbException; + + /** + * Responds to a pending blog invitation + */ + void respondToInvitation(Blog b, Contact c, boolean accept) + throws DbException; + + /** + * Returns all blogs sharing messages sent by the Contact + * identified by contactId. + */ + Collection<BlogInvitationMessage> getInvitationMessages( + ContactId contactId) throws DbException; + + /** + * Returns all blogs to which the user could subscribe. + */ + Collection<Blog> getAvailable() throws DbException; + + /** + * Returns all contacts who are sharing the given blog with us. + */ + Collection<Contact> getSharedBy(GroupId g) throws DbException; + + /** + * Returns the IDs of all contacts with whom the given blog is shared. + */ + Collection<Contact> getSharedWith(GroupId g) throws DbException; + + /** + * Returns true if the blog not already shared and no invitation is open + */ + boolean canBeShared(GroupId g, Contact c) throws DbException; + +} diff --git a/briar-api/src/org/briarproject/api/blogs/BlogSharingMessage.java b/briar-api/src/org/briarproject/api/blogs/BlogSharingMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..105b0d2a3f981c27db33f36fbc072b296f93689c --- /dev/null +++ b/briar-api/src/org/briarproject/api/blogs/BlogSharingMessage.java @@ -0,0 +1,89 @@ +package org.briarproject.api.blogs; + +import org.briarproject.api.FormatException; +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.data.BdfList; +import org.briarproject.api.sharing.SharingMessage.Invitation; +import org.briarproject.api.sync.GroupId; + +import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME; +import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC; +import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY; +import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE; +import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG; +import static org.briarproject.api.sharing.SharingConstants.SESSION_ID; + +public interface BlogSharingMessage { + + class BlogInvitation extends Invitation { + + private final String blogTitle; + private final String blogDesc; + private final String blogAuthorName; + private final byte[] blogPublicKey; + + public BlogInvitation(GroupId groupId, SessionId sessionId, + String blogTitle, String blogDesc, String blogAuthorName, + byte[] blogPublicKey, String message) { + + super(groupId, sessionId, message); + + this.blogTitle = blogTitle; + this.blogDesc = blogDesc; + this.blogAuthorName = blogAuthorName; + this.blogPublicKey = blogPublicKey; + } + + @Override + public BdfList toBdfList() { + BdfList list = super.toBdfList(); + list.add(blogTitle); + list.add(blogDesc); + list.add(BdfList.of(blogAuthorName, blogPublicKey)); + if (message != null) list.add(message); + return list; + } + + @Override + public BdfDictionary toBdfDictionary() { + BdfDictionary d = toBdfDictionaryHelper(); + d.put(BLOG_TITLE, blogTitle); + d.put(BLOG_DESC, blogDesc); + d.put(BLOG_AUTHOR_NAME, blogAuthorName); + d.put(BLOG_PUBLIC_KEY, blogPublicKey); + if (message != null) d.put(INVITATION_MSG, message); + return d; + } + + public static BlogInvitation from(GroupId groupId, BdfDictionary d) + throws FormatException { + + SessionId sessionId = new SessionId(d.getRaw(SESSION_ID)); + String blogTitle = d.getString(BLOG_TITLE); + String blogDesc = d.getString(BLOG_DESC); + String blogAuthorName = d.getString(BLOG_AUTHOR_NAME); + byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY); + String message = d.getOptionalString(INVITATION_MSG); + + return new BlogInvitation(groupId, sessionId, blogTitle, + blogDesc, blogAuthorName, blogPublicKey, message); + } + + public String getBlogTitle() { + return blogTitle; + } + + public String getBlogDesc() { + return blogDesc; + } + + public String getBlogAuthorName() { + return blogAuthorName; + } + + public byte[] getBlogPublicKey() { + return blogPublicKey; + } + } +} diff --git a/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java b/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..12d8d4cc4b8dec2dd91f2cf4bf1f80322f56f421 --- /dev/null +++ b/briar-api/src/org/briarproject/api/event/BlogInvitationReceivedEvent.java @@ -0,0 +1,18 @@ +package org.briarproject.api.event; + +import org.briarproject.api.blogs.Blog; +import org.briarproject.api.contact.ContactId; + +public class BlogInvitationReceivedEvent extends InvitationReceivedEvent { + + private final Blog blog; + + public BlogInvitationReceivedEvent(Blog blog, ContactId contactId) { + super(contactId); + this.blog = blog; + } + + public Blog getBlog() { + return blog; + } +} diff --git a/briar-api/src/org/briarproject/api/event/BlogInvitationResponseReceivedEvent.java b/briar-api/src/org/briarproject/api/event/BlogInvitationResponseReceivedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..b6344ad928dd3c5e14155ad7c8dd7c70c69e3f38 --- /dev/null +++ b/briar-api/src/org/briarproject/api/event/BlogInvitationResponseReceivedEvent.java @@ -0,0 +1,18 @@ +package org.briarproject.api.event; + +import org.briarproject.api.contact.ContactId; + +public class BlogInvitationResponseReceivedEvent extends InvitationResponseReceivedEvent { + + private final String blogTitle; + + public BlogInvitationResponseReceivedEvent(String blogTitle, + ContactId contactId) { + super(contactId); + this.blogTitle = blogTitle; + } + + public String getBlogTitle() { + return blogTitle; + } +} diff --git a/briar-api/src/org/briarproject/api/event/ForumInvitationReceivedEvent.java b/briar-api/src/org/briarproject/api/event/ForumInvitationReceivedEvent.java index 1d8e7b5f7b61a1a88076277e48fb3b52cc34de13..63aa3bce19810f3ba450e7eeeed6799c070a881f 100644 --- a/briar-api/src/org/briarproject/api/event/ForumInvitationReceivedEvent.java +++ b/briar-api/src/org/briarproject/api/event/ForumInvitationReceivedEvent.java @@ -4,21 +4,16 @@ import org.briarproject.api.contact.ContactId; import org.briarproject.api.forum.Forum; import org.briarproject.api.introduction.IntroductionRequest; -public class ForumInvitationReceivedEvent extends Event { +public class ForumInvitationReceivedEvent extends InvitationReceivedEvent { private final Forum forum; - private final ContactId contactId; public ForumInvitationReceivedEvent(Forum forum, ContactId contactId) { + super(contactId); this.forum = forum; - this.contactId = contactId; } public Forum getForum() { return forum; } - - public ContactId getContactId() { - return contactId; - } } diff --git a/briar-api/src/org/briarproject/api/event/ForumInvitationResponseReceivedEvent.java b/briar-api/src/org/briarproject/api/event/ForumInvitationResponseReceivedEvent.java index 1e799240386966ff59c73037c97e6cfaaaeb2e63..cb51daf0a2c05b8f97b3097a4ee7ee2eec48caf3 100644 --- a/briar-api/src/org/briarproject/api/event/ForumInvitationResponseReceivedEvent.java +++ b/briar-api/src/org/briarproject/api/event/ForumInvitationResponseReceivedEvent.java @@ -2,23 +2,17 @@ package org.briarproject.api.event; import org.briarproject.api.contact.ContactId; -public class ForumInvitationResponseReceivedEvent extends Event { +public class ForumInvitationResponseReceivedEvent extends InvitationResponseReceivedEvent { private final String forumName; - private final ContactId contactId; public ForumInvitationResponseReceivedEvent(String forumName, ContactId contactId) { - + super(contactId); this.forumName = forumName; - this.contactId = contactId; } public String getForumName() { return forumName; } - - public ContactId getContactId() { - return contactId; - } } diff --git a/briar-api/src/org/briarproject/api/event/InvitationReceivedEvent.java b/briar-api/src/org/briarproject/api/event/InvitationReceivedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..4b1b6df2d36fb18f0e41124919571cc04a5d415a --- /dev/null +++ b/briar-api/src/org/briarproject/api/event/InvitationReceivedEvent.java @@ -0,0 +1,17 @@ +package org.briarproject.api.event; + +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.forum.Forum; + +public abstract class InvitationReceivedEvent extends Event { + + private final ContactId contactId; + + public InvitationReceivedEvent(ContactId contactId) { + this.contactId = contactId; + } + + public ContactId getContactId() { + return contactId; + } +} diff --git a/briar-api/src/org/briarproject/api/event/InvitationResponseReceivedEvent.java b/briar-api/src/org/briarproject/api/event/InvitationResponseReceivedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..df84a69656d5cbb38ff78843e37397eec676454d --- /dev/null +++ b/briar-api/src/org/briarproject/api/event/InvitationResponseReceivedEvent.java @@ -0,0 +1,16 @@ +package org.briarproject.api.event; + +import org.briarproject.api.contact.ContactId; + +public abstract class InvitationResponseReceivedEvent extends Event { + + private final ContactId contactId; + + public InvitationResponseReceivedEvent(ContactId contactId) { + this.contactId = contactId; + } + + public ContactId getContactId() { + return contactId; + } +} diff --git a/briar-api/src/org/briarproject/api/forum/Forum.java b/briar-api/src/org/briarproject/api/forum/Forum.java index 2eeadc21664f069e32db944305a5d0756ec05561..61628250829fe871c0e7436d36efb28d3303c9b1 100644 --- a/briar-api/src/org/briarproject/api/forum/Forum.java +++ b/briar-api/src/org/briarproject/api/forum/Forum.java @@ -1,9 +1,10 @@ package org.briarproject.api.forum; +import org.briarproject.api.sharing.Shareable; import org.briarproject.api.sync.Group; import org.briarproject.api.sync.GroupId; -public class Forum { +public class Forum implements Shareable { private final Group group; private final String name; diff --git a/briar-api/src/org/briarproject/api/forum/ForumConstants.java b/briar-api/src/org/briarproject/api/forum/ForumConstants.java index 0bbf8896bc9ac7757d1af47bb1cf28947e902cd7..9523b20cc8eb1fbdd73974a6461671acc19a08a6 100644 --- a/briar-api/src/org/briarproject/api/forum/ForumConstants.java +++ b/briar-api/src/org/briarproject/api/forum/ForumConstants.java @@ -17,37 +17,8 @@ public interface ForumConstants { int MAX_FORUM_POST_BODY_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024; /* Forum Sharing Constants */ - String CONTACT_ID = "contactId"; - String GROUP_ID = "groupId"; - String TO_BE_SHARED_BY_US = "toBeSharedByUs"; - String SHARED_BY_US = "sharedByUs"; - String SHARED_WITH_US = "sharedWithUs"; - String TYPE = "type"; - String SESSION_ID = "sessionId"; - String STORAGE_ID = "storageId"; - String STATE = "state"; - String LOCAL = "local"; - String TIME = "time"; - String READ = "read"; - String IS_SHARER = "isSharer"; - String FORUM_ID = "forumId"; String FORUM_NAME = "forumName"; String FORUM_SALT = "forumSalt"; - String INVITATION_MSG = "invitationMsg"; - int SHARE_MSG_TYPE_INVITATION = 1; - int SHARE_MSG_TYPE_ACCEPT = 2; - int SHARE_MSG_TYPE_DECLINE = 3; - int SHARE_MSG_TYPE_LEAVE = 4; - int SHARE_MSG_TYPE_ABORT = 5; - String TASK = "task"; - int TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US = 0; - int TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US = 1; - int TASK_ADD_SHARED_FORUM = 2; - int TASK_ADD_FORUM_TO_LIST_TO_BE_SHARED_BY_US = 3; - int TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US = 4; - int TASK_SHARE_FORUM = 5; - int TASK_UNSHARE_FORUM_SHARED_BY_US = 6; - int TASK_UNSHARE_FORUM_SHARED_WITH_US = 7; // Database keys String KEY_TIMESTAMP = "timestamp"; diff --git a/briar-api/src/org/briarproject/api/forum/ForumInvitationMessage.java b/briar-api/src/org/briarproject/api/forum/ForumInvitationMessage.java index b153c27f11cb996d5b48f3ad3ebb4aa47e17475d..fd2d6b0d8c464bdbdce0644a3c03e1401774c5df 100644 --- a/briar-api/src/org/briarproject/api/forum/ForumInvitationMessage.java +++ b/briar-api/src/org/briarproject/api/forum/ForumInvitationMessage.java @@ -3,46 +3,25 @@ package org.briarproject.api.forum; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.messaging.BaseMessage; +import org.briarproject.api.sharing.InvitationMessage; import org.briarproject.api.sync.MessageId; -public class ForumInvitationMessage extends BaseMessage { +public class ForumInvitationMessage extends InvitationMessage { - private final SessionId sessionId; - private final ContactId contactId; - private final String forumName, message; - private final boolean available; + private final String forumName; public ForumInvitationMessage(MessageId id, SessionId sessionId, ContactId contactId, String forumName, String message, boolean available, long time, boolean local, boolean sent, boolean seen, boolean read) { - super(id, time, local, read, sent, seen); - this.sessionId = sessionId; - this.contactId = contactId; + super(id, sessionId, contactId, message, available, time, local, sent, + seen, read); this.forumName = forumName; - this.message = message; - this.available = available; - } - - public SessionId getSessionId() { - return sessionId; - } - - public ContactId getContactId() { - return contactId; } public String getForumName() { return forumName; } - public String getMessage() { - return message; - } - - public boolean isAvailable() { - return available; - } - } diff --git a/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java b/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java index e38f13149e3b5be1da682efcd94b0c6eee6e0e00..55da0615f9134ee0d6a1c89f62a0d53fcef7321c 100644 --- a/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java +++ b/briar-api/src/org/briarproject/api/forum/ForumSharingManager.java @@ -1,15 +1,15 @@ package org.briarproject.api.forum; -import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; import org.briarproject.api.db.DbException; +import org.briarproject.api.sharing.SharingManager; import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.GroupId; import java.util.Collection; -public interface ForumSharingManager { +public interface ForumSharingManager extends SharingManager<Forum, ForumInvitationMessage> { /** Returns the unique ID of the forum sharing client. */ ClientId getClientId(); @@ -18,7 +18,7 @@ public interface ForumSharingManager { * Sends an invitation to share the given forum with the given contact * and sends an optional message along with it. */ - void sendForumInvitation(GroupId groupId, ContactId contactId, + void sendInvitation(GroupId groupId, ContactId contactId, String message) throws DbException; /** @@ -31,11 +31,11 @@ public interface ForumSharingManager { * Returns all forum sharing messages sent by the Contact * identified by contactId. */ - Collection<ForumInvitationMessage> getForumInvitationMessages( + Collection<ForumInvitationMessage> getInvitationMessages( ContactId contactId) throws DbException; /** Returns all forums to which the user could subscribe. */ - Collection<Forum> getAvailableForums() throws DbException; + Collection<Forum> getAvailable() throws DbException; /** Returns all contacts who are sharing the given forum with us. */ Collection<Contact> getSharedBy(GroupId g) throws DbException; diff --git a/briar-api/src/org/briarproject/api/forum/ForumSharingMessage.java b/briar-api/src/org/briarproject/api/forum/ForumSharingMessage.java index 79a43ad6649010bdea912efbe12026f525f43203..45badea54948e5b5100263a194ed141cdd2abd5e 100644 --- a/briar-api/src/org/briarproject/api/forum/ForumSharingMessage.java +++ b/briar-api/src/org/briarproject/api/forum/ForumSharingMessage.java @@ -3,89 +3,29 @@ package org.briarproject.api.forum; import org.briarproject.api.FormatException; import org.briarproject.api.clients.SessionId; import org.briarproject.api.data.BdfDictionary; -import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfList; +import org.briarproject.api.sharing.SharingMessage.Invitation; import org.briarproject.api.sync.GroupId; import static org.briarproject.api.forum.ForumConstants.FORUM_NAME; import static org.briarproject.api.forum.ForumConstants.FORUM_SALT; -import static org.briarproject.api.forum.ForumConstants.GROUP_ID; -import static org.briarproject.api.forum.ForumConstants.INVITATION_MSG; -import static org.briarproject.api.forum.ForumConstants.SESSION_ID; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ACCEPT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_DECLINE; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_INVITATION; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.api.forum.ForumConstants.TYPE; +import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG; +import static org.briarproject.api.sharing.SharingConstants.SESSION_ID; public interface ForumSharingMessage { - abstract class BaseMessage { - private final GroupId groupId; - private final SessionId sessionId; - - public BaseMessage(GroupId groupId, SessionId sessionId) { - - this.groupId = groupId; - this.sessionId = sessionId; - } - - public BdfList toBdfList() { - return BdfList.of(getType(), getSessionId()); - } - - public abstract BdfDictionary toBdfDictionary(); - - protected BdfDictionary toBdfDictionaryHelper() { - return BdfDictionary.of( - new BdfEntry(TYPE, getType()), - new BdfEntry(GROUP_ID, groupId), - new BdfEntry(SESSION_ID, sessionId) - ); - } - - public static BaseMessage from(GroupId groupId, BdfDictionary d) - throws FormatException { - - long type = d.getLong(TYPE); - - if (type == SHARE_MSG_TYPE_INVITATION) - return Invitation.from(groupId, d); - else - return SimpleMessage.from(type, groupId, d); - } - - public abstract long getType(); - - public GroupId getGroupId() { - return groupId; - } - - public SessionId getSessionId() { - return sessionId; - } - } - - class Invitation extends BaseMessage { + class ForumInvitation extends Invitation { private final String forumName; private final byte[] forumSalt; - private final String message; - public Invitation(GroupId groupId, SessionId sessionId, + public ForumInvitation(GroupId groupId, SessionId sessionId, String forumName, byte[] forumSalt, String message) { - super(groupId, sessionId); + super(groupId, sessionId, message); this.forumName = forumName; this.forumSalt = forumSalt; - this.message = message; - } - - @Override - public long getType() { - return SHARE_MSG_TYPE_INVITATION; } @Override @@ -106,7 +46,7 @@ public interface ForumSharingMessage { return d; } - public static Invitation from(GroupId groupId, BdfDictionary d) + public static ForumInvitation from(GroupId groupId, BdfDictionary d) throws FormatException { SessionId sessionId = new SessionId(d.getRaw(SESSION_ID)); @@ -114,7 +54,7 @@ public interface ForumSharingMessage { byte[] forumSalt = d.getRaw(FORUM_SALT); String message = d.getOptionalString(INVITATION_MSG); - return new Invitation(groupId, sessionId, forumName, forumSalt, + return new ForumInvitation(groupId, sessionId, forumName, forumSalt, message); } @@ -125,42 +65,5 @@ public interface ForumSharingMessage { public byte[] getForumSalt() { return forumSalt; } - - public String getMessage() { - return message; - } - } - - class SimpleMessage extends BaseMessage { - - private final long type; - - public SimpleMessage(long type, GroupId groupId, SessionId sessionId) { - super(groupId, sessionId); - this.type = type; - } - - @Override - public long getType() { - return type; - } - - @Override - public BdfDictionary toBdfDictionary() { - return toBdfDictionaryHelper(); - } - - public static SimpleMessage from(long type, GroupId groupId, - BdfDictionary d) throws FormatException { - - if (type != SHARE_MSG_TYPE_ACCEPT && - type != SHARE_MSG_TYPE_DECLINE && - type != SHARE_MSG_TYPE_LEAVE && - type != SHARE_MSG_TYPE_ABORT) throw new FormatException(); - - SessionId sessionId = new SessionId(d.getRaw(SESSION_ID)); - return new SimpleMessage(type, groupId, sessionId); - } } - } diff --git a/briar-api/src/org/briarproject/api/sharing/InvitationFactory.java b/briar-api/src/org/briarproject/api/sharing/InvitationFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..1f8548d38433666d25719ce8ed3a799eabe19ba9 --- /dev/null +++ b/briar-api/src/org/briarproject/api/sharing/InvitationFactory.java @@ -0,0 +1,10 @@ +package org.briarproject.api.sharing; + +import org.briarproject.api.FormatException; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.sync.GroupId; + +public interface InvitationFactory<I extends SharingMessage.Invitation> { + + I build(GroupId groupId, BdfDictionary d) throws FormatException; +} diff --git a/briar-api/src/org/briarproject/api/sharing/InvitationMessage.java b/briar-api/src/org/briarproject/api/sharing/InvitationMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..4d3c12e26188945ef59cdf7809c254c1d5b3dadc --- /dev/null +++ b/briar-api/src/org/briarproject/api/sharing/InvitationMessage.java @@ -0,0 +1,43 @@ +package org.briarproject.api.sharing; + +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.messaging.BaseMessage; +import org.briarproject.api.sync.MessageId; + +public abstract class InvitationMessage extends BaseMessage { + + private final SessionId sessionId; + private final ContactId contactId; + private final String message; + private final boolean available; + + public InvitationMessage(MessageId id, SessionId sessionId, + ContactId contactId, String message, + boolean available, long time, boolean local, boolean sent, + boolean seen, boolean read) { + + super(id, time, local, read, sent, seen); + this.sessionId = sessionId; + this.contactId = contactId; + this.message = message; + this.available = available; + } + + public SessionId getSessionId() { + return sessionId; + } + + public ContactId getContactId() { + return contactId; + } + + public String getMessage() { + return message; + } + + public boolean isAvailable() { + return available; + } + +} diff --git a/briar-api/src/org/briarproject/api/sharing/Shareable.java b/briar-api/src/org/briarproject/api/sharing/Shareable.java new file mode 100644 index 0000000000000000000000000000000000000000..13c11fdeeff5b39d3f775b293281bcfabc08d097 --- /dev/null +++ b/briar-api/src/org/briarproject/api/sharing/Shareable.java @@ -0,0 +1,11 @@ +package org.briarproject.api.sharing; + +import org.briarproject.api.sync.Group; +import org.briarproject.api.sync.GroupId; + +public interface Shareable { + + GroupId getId(); + + Group getGroup(); +} diff --git a/briar-api/src/org/briarproject/api/sharing/SharingConstants.java b/briar-api/src/org/briarproject/api/sharing/SharingConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..952bfd6602b2c3956c287c17bad66abe1cb30fe0 --- /dev/null +++ b/briar-api/src/org/briarproject/api/sharing/SharingConstants.java @@ -0,0 +1,38 @@ +package org.briarproject.api.sharing; + +public interface SharingConstants { + + /** The length of a sharing session's random salt in bytes. */ + int SHARING_SALT_LENGTH = 32; + + String CONTACT_ID = "contactId"; + String GROUP_ID = "groupId"; + String TO_BE_SHARED_BY_US = "toBeSharedByUs"; + String SHARED_BY_US = "sharedByUs"; + String SHARED_WITH_US = "sharedWithUs"; + String TYPE = "type"; + String SESSION_ID = "sessionId"; + String STORAGE_ID = "storageId"; + String STATE = "state"; + String LOCAL = "local"; + String TIME = "time"; + String READ = "read"; + String IS_SHARER = "isSharer"; + String SHAREABLE_ID = "shareableId"; + String INVITATION_MSG = "invitationMsg"; + int SHARE_MSG_TYPE_INVITATION = 1; + int SHARE_MSG_TYPE_ACCEPT = 2; + int SHARE_MSG_TYPE_DECLINE = 3; + int SHARE_MSG_TYPE_LEAVE = 4; + int SHARE_MSG_TYPE_ABORT = 5; + String TASK = "task"; + int TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US = 0; + int TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US = 1; + int TASK_ADD_SHARED_SHAREABLE = 2; + int TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US = 3; + int TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US = 4; + int TASK_SHARE_SHAREABLE = 5; + int TASK_UNSHARE_SHAREABLE_SHARED_BY_US = 6; + int TASK_UNSHARE_SHAREABLE_SHARED_WITH_US = 7; + +} diff --git a/briar-api/src/org/briarproject/api/sharing/SharingManager.java b/briar-api/src/org/briarproject/api/sharing/SharingManager.java new file mode 100644 index 0000000000000000000000000000000000000000..8c5db480b7058bf63d4730a8f6d9c406c119fd49 --- /dev/null +++ b/briar-api/src/org/briarproject/api/sharing/SharingManager.java @@ -0,0 +1,50 @@ +package org.briarproject.api.sharing; + +import org.briarproject.api.contact.Contact; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.db.DbException; +import org.briarproject.api.forum.Forum; +import org.briarproject.api.forum.ForumInvitationMessage; +import org.briarproject.api.sync.ClientId; +import org.briarproject.api.sync.GroupId; + +import java.util.Collection; + +public interface SharingManager<S extends Shareable, IM extends InvitationMessage> { + + /** Returns the unique ID of the group sharing client. */ + ClientId getClientId(); + + /** + * Sends an invitation to share the given group with the given contact + * and sends an optional message along with it. + */ + void sendInvitation(GroupId groupId, ContactId contactId, + String message) throws DbException; + + /** + * Responds to a pending group invitation + */ + void respondToInvitation(S s, Contact c, boolean accept) + throws DbException; + + /** + * Returns all group sharing messages sent by the Contact + * identified by contactId. + */ + Collection<IM> getInvitationMessages( + ContactId contactId) throws DbException; + + /** Returns all groups to which the user could subscribe. */ + Collection<S> getAvailable() throws DbException; + + /** Returns all contacts who are sharing the given group with us. */ + Collection<Contact> getSharedBy(GroupId g) throws DbException; + + /** Returns the IDs of all contacts with whom the given group is shared. */ + Collection<Contact> getSharedWith(GroupId g) throws DbException; + + /** Returns true if the group not already shared and no invitation is open */ + boolean canBeShared(GroupId g, Contact c) throws DbException; + +} diff --git a/briar-api/src/org/briarproject/api/sharing/SharingMessage.java b/briar-api/src/org/briarproject/api/sharing/SharingMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..78433ff6fa5ba601ff71a0a9c6c83cbb5bbefdae --- /dev/null +++ b/briar-api/src/org/briarproject/api/sharing/SharingMessage.java @@ -0,0 +1,122 @@ +package org.briarproject.api.sharing; + +import org.briarproject.api.FormatException; +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.data.BdfEntry; +import org.briarproject.api.data.BdfList; +import org.briarproject.api.sync.GroupId; + +import static org.briarproject.api.sharing.SharingConstants.GROUP_ID; +import static org.briarproject.api.sharing.SharingConstants.SESSION_ID; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; +import static org.briarproject.api.sharing.SharingConstants.TYPE; + +public interface SharingMessage { + + abstract class BaseMessage { + private final GroupId groupId; + private final SessionId sessionId; + + public BaseMessage(GroupId groupId, SessionId sessionId) { + + this.groupId = groupId; + this.sessionId = sessionId; + } + + public BdfList toBdfList() { + return BdfList.of(getType(), getSessionId()); + } + + public abstract BdfDictionary toBdfDictionary(); + + protected BdfDictionary toBdfDictionaryHelper() { + return BdfDictionary.of( + new BdfEntry(TYPE, getType()), + new BdfEntry(GROUP_ID, groupId), + new BdfEntry(SESSION_ID, sessionId) + ); + } + + public static BaseMessage from(InvitationFactory invitationFactory, + GroupId groupId, BdfDictionary d) + throws FormatException { + + long type = d.getLong(TYPE); + + if (type == SHARE_MSG_TYPE_INVITATION) + return invitationFactory.build(groupId, d); + else + return SimpleMessage.from(type, groupId, d); + } + + public abstract long getType(); + + public GroupId getGroupId() { + return groupId; + } + + public SessionId getSessionId() { + return sessionId; + } + } + + abstract class Invitation extends BaseMessage { + + protected final String message; + + public Invitation(GroupId groupId, SessionId sessionId, + String message) { + + super(groupId, sessionId); + + this.message = message; + } + + @Override + public long getType() { + return SHARE_MSG_TYPE_INVITATION; + } + + public String getMessage() { + return message; + } + } + + class SimpleMessage extends BaseMessage { + + private final long type; + + public SimpleMessage(long type, GroupId groupId, SessionId sessionId) { + super(groupId, sessionId); + this.type = type; + } + + @Override + public long getType() { + return type; + } + + @Override + public BdfDictionary toBdfDictionary() { + return toBdfDictionaryHelper(); + } + + public static SimpleMessage from(long type, GroupId groupId, + BdfDictionary d) throws FormatException { + + if (type != SHARE_MSG_TYPE_ACCEPT && + type != SHARE_MSG_TYPE_DECLINE && + type != SHARE_MSG_TYPE_LEAVE && + type != SHARE_MSG_TYPE_ABORT) throw new FormatException(); + + SessionId sessionId = new SessionId(d.getRaw(SESSION_ID)); + return new SimpleMessage(type, groupId, sessionId); + } + } + +} diff --git a/briar-core/src/org/briarproject/CoreEagerSingletons.java b/briar-core/src/org/briarproject/CoreEagerSingletons.java index 6847f461220bebd4b3131b09af88e6d253c5c677..d7b0c1bee1c8c725d7ede60ecd9f11356adef455 100644 --- a/briar-core/src/org/briarproject/CoreEagerSingletons.java +++ b/briar-core/src/org/briarproject/CoreEagerSingletons.java @@ -10,6 +10,7 @@ import org.briarproject.lifecycle.LifecycleModule; import org.briarproject.messaging.MessagingModule; import org.briarproject.plugins.PluginsModule; import org.briarproject.properties.PropertiesModule; +import org.briarproject.sharing.SharingModule; import org.briarproject.sync.SyncModule; import org.briarproject.system.SystemModule; import org.briarproject.transport.TransportModule; @@ -36,6 +37,8 @@ public interface CoreEagerSingletons { void inject(PropertiesModule.EagerSingletons init); + void inject(SharingModule.EagerSingletons init); + void inject(SyncModule.EagerSingletons init); void inject(SystemModule.EagerSingletons init); diff --git a/briar-core/src/org/briarproject/CoreModule.java b/briar-core/src/org/briarproject/CoreModule.java index 6a909b3f6d8110b63a4348cee50012283ef6d2d2..140f0b7e67f1ef6437c65a7ca1d052b0568786c5 100644 --- a/briar-core/src/org/briarproject/CoreModule.java +++ b/briar-core/src/org/briarproject/CoreModule.java @@ -20,6 +20,7 @@ import org.briarproject.properties.PropertiesModule; import org.briarproject.reliability.ReliabilityModule; import org.briarproject.reporting.ReportingModule; import org.briarproject.settings.SettingsModule; +import org.briarproject.sharing.SharingModule; import org.briarproject.sync.SyncModule; import org.briarproject.system.SystemModule; import org.briarproject.transport.TransportModule; @@ -47,6 +48,7 @@ import dagger.Module; ReliabilityModule.class, ReportingModule.class, SettingsModule.class, + SharingModule.class, SyncModule.class, SystemModule.class, TransportModule.class @@ -63,6 +65,7 @@ public class CoreModule { c.inject(new MessagingModule.EagerSingletons()); c.inject(new PluginsModule.EagerSingletons()); c.inject(new PropertiesModule.EagerSingletons()); + c.inject(new SharingModule.EagerSingletons()); c.inject(new SyncModule.EagerSingletons()); c.inject(new SystemModule.EagerSingletons()); c.inject(new TransportModule.EagerSingletons()); diff --git a/briar-core/src/org/briarproject/forum/ForumModule.java b/briar-core/src/org/briarproject/forum/ForumModule.java index 59f56af2acf07df4a8595430239f8cf8f541cc13..8c84509b143bf3c45a082b9829d3acdb9e016fa3 100644 --- a/briar-core/src/org/briarproject/forum/ForumModule.java +++ b/briar-core/src/org/briarproject/forum/ForumModule.java @@ -1,18 +1,12 @@ package org.briarproject.forum; import org.briarproject.api.clients.ClientHelper; -import org.briarproject.api.clients.MessageQueueManager; -import org.briarproject.api.contact.ContactManager; import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.data.MetadataEncoder; -import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.forum.ForumFactory; import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumPostFactory; -import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.identity.AuthorFactory; -import org.briarproject.api.identity.IdentityManager; -import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.sync.GroupFactory; import org.briarproject.api.sync.ValidationManager; import org.briarproject.api.system.Clock; @@ -31,10 +25,6 @@ public class ForumModule { public static class EagerSingletons { @Inject ForumPostValidator forumPostValidator; - @Inject - ForumSharingValidator forumSharingValidator; - @Inject - ForumSharingManager forumSharingManager; } @Provides @@ -68,37 +58,4 @@ public class ForumModule { return validator; } - @Provides - @Singleton - ForumSharingValidator provideSharingValidator( - MessageQueueManager messageQueueManager, ClientHelper clientHelper, - MetadataEncoder metadataEncoder, Clock clock) { - - ForumSharingValidator validator = new ForumSharingValidator(clientHelper, - metadataEncoder, clock); - messageQueueManager.registerMessageValidator( - ForumSharingManagerImpl.CLIENT_ID, validator); - - return validator; - } - - @Provides - @Singleton - ForumSharingManager provideForumSharingManager( - LifecycleManager lifecycleManager, - ContactManager contactManager, - MessageQueueManager messageQueueManager, - ForumManager forumManager, - ForumSharingManagerImpl forumSharingManager) { - - lifecycleManager.registerClient(forumSharingManager); - contactManager.registerAddContactHook(forumSharingManager); - contactManager.registerRemoveContactHook(forumSharingManager); - messageQueueManager.registerIncomingMessageHook( - ForumSharingManagerImpl.CLIENT_ID, forumSharingManager); - forumManager.registerRemoveForumHook(forumSharingManager); - - return forumSharingManager; - } - } diff --git a/briar-core/src/org/briarproject/forum/ForumSharingSessionState.java b/briar-core/src/org/briarproject/forum/ForumSharingSessionState.java deleted file mode 100644 index dc2e69bfb38ecbc5ec72f1d83080c1618207f3ad..0000000000000000000000000000000000000000 --- a/briar-core/src/org/briarproject/forum/ForumSharingSessionState.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.briarproject.forum; - -import org.briarproject.api.FormatException; -import org.briarproject.api.clients.SessionId; -import org.briarproject.api.contact.ContactId; -import org.briarproject.api.data.BdfDictionary; -import org.briarproject.api.sync.GroupId; -import org.briarproject.api.sync.MessageId; - -import static org.briarproject.api.forum.ForumConstants.CONTACT_ID; -import static org.briarproject.api.forum.ForumConstants.FORUM_ID; -import static org.briarproject.api.forum.ForumConstants.FORUM_NAME; -import static org.briarproject.api.forum.ForumConstants.FORUM_SALT; -import static org.briarproject.api.forum.ForumConstants.GROUP_ID; -import static org.briarproject.api.forum.ForumConstants.IS_SHARER; -import static org.briarproject.api.forum.ForumConstants.SESSION_ID; -import static org.briarproject.api.forum.ForumConstants.STATE; -import static org.briarproject.api.forum.ForumConstants.STORAGE_ID; - -// This class is not thread-safe -public abstract class ForumSharingSessionState { - - private final SessionId sessionId; - private final MessageId storageId; - private final GroupId groupId; - private final ContactId contactId; - private final GroupId forumId; - private final String forumName; - private final byte[] forumSalt; - private int task = -1; // TODO get rid of task, see #376 - - public ForumSharingSessionState(SessionId sessionId, MessageId storageId, - GroupId groupId, ContactId contactId, GroupId forumId, - String forumName, byte[] forumSalt) { - - this.sessionId = sessionId; - this.storageId = storageId; - this.groupId = groupId; - this.contactId = contactId; - this.forumId = forumId; - this.forumName = forumName; - this.forumSalt = forumSalt; - } - - public static ForumSharingSessionState fromBdfDictionary(BdfDictionary d) - throws FormatException{ - - SessionId sessionId = new SessionId(d.getRaw(SESSION_ID)); - MessageId messageId = new MessageId(d.getRaw(STORAGE_ID)); - GroupId groupId = new GroupId(d.getRaw(GROUP_ID)); - ContactId contactId = new ContactId(d.getLong(CONTACT_ID).intValue()); - GroupId forumId = new GroupId(d.getRaw(FORUM_ID)); - String forumName = d.getString(FORUM_NAME); - byte[] forumSalt = d.getRaw(FORUM_SALT); - - int intState = d.getLong(STATE).intValue(); - if (d.getBoolean(IS_SHARER)) { - SharerSessionState.State state = - SharerSessionState.State.fromValue(intState); - return new SharerSessionState(sessionId, messageId, groupId, state, - contactId, forumId, forumName, forumSalt); - } else { - InviteeSessionState.State state = - InviteeSessionState.State.fromValue(intState); - return new InviteeSessionState(sessionId, messageId, groupId, state, - contactId, forumId, forumName, forumSalt); - } - } - - public BdfDictionary toBdfDictionary() { - BdfDictionary d = new BdfDictionary(); - d.put(SESSION_ID, getSessionId()); - d.put(STORAGE_ID, getStorageId()); - d.put(GROUP_ID, getGroupId()); - d.put(CONTACT_ID, getContactId().getInt()); - d.put(FORUM_ID, getForumId()); - d.put(FORUM_NAME, getForumName()); - d.put(FORUM_SALT, getForumSalt()); - - return d; - } - - public SessionId getSessionId() { - return sessionId; - } - - public MessageId getStorageId() { - return storageId; - } - - public GroupId getGroupId() { - return groupId; - } - - public ContactId getContactId() { - return contactId; - } - - public GroupId getForumId() { - return forumId; - } - - public String getForumName() { - return forumName; - } - - public byte[] getForumSalt() { - return forumSalt; - } - - public void setTask(int task) { - this.task = task; - } - - public int getTask() { - return task; - } - -} \ No newline at end of file diff --git a/briar-core/src/org/briarproject/forum/InviteeEngine.java b/briar-core/src/org/briarproject/forum/InviteeEngine.java deleted file mode 100644 index c7c9ff6223c159fb163d6e6504d81c5600cc4246..0000000000000000000000000000000000000000 --- a/briar-core/src/org/briarproject/forum/InviteeEngine.java +++ /dev/null @@ -1,239 +0,0 @@ -package org.briarproject.forum; - -import org.briarproject.api.FormatException; -import org.briarproject.api.clients.ProtocolEngine; -import org.briarproject.api.contact.ContactId; -import org.briarproject.api.event.Event; -import org.briarproject.api.event.ForumInvitationReceivedEvent; -import org.briarproject.api.forum.Forum; -import org.briarproject.api.forum.ForumFactory; - -import java.util.Collections; -import java.util.List; -import java.util.logging.Logger; - -import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ACCEPT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_DECLINE; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_INVITATION; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.api.forum.ForumConstants.TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US; -import static org.briarproject.api.forum.ForumConstants.TASK_ADD_SHARED_FORUM; -import static org.briarproject.api.forum.ForumConstants.TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US; -import static org.briarproject.api.forum.ForumConstants.TASK_UNSHARE_FORUM_SHARED_WITH_US; -import static org.briarproject.api.forum.ForumSharingMessage.SimpleMessage; -import static org.briarproject.api.forum.ForumSharingMessage.BaseMessage; -import static org.briarproject.forum.InviteeSessionState.Action; -import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_ABORT; -import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_ACCEPT; -import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_DECLINE; -import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_LEAVE; -import static org.briarproject.forum.InviteeSessionState.Action.REMOTE_INVITATION; -import static org.briarproject.forum.InviteeSessionState.Action.REMOTE_LEAVE; -import static org.briarproject.forum.InviteeSessionState.State; -import static org.briarproject.forum.InviteeSessionState.State.ERROR; -import static org.briarproject.forum.InviteeSessionState.State.FINISHED; -import static org.briarproject.forum.InviteeSessionState.State.LEFT; - -public class InviteeEngine - implements ProtocolEngine<Action, InviteeSessionState, BaseMessage> { - - private final ForumFactory forumFactory; - private static final Logger LOG = - Logger.getLogger(SharerEngine.class.getName()); - - InviteeEngine(ForumFactory forumFactory) { - this.forumFactory = forumFactory; - } - - @Override - public StateUpdate<InviteeSessionState, BaseMessage> onLocalAction( - InviteeSessionState localState, Action action) { - - try { - State currentState = localState.getState(); - State nextState = currentState.next(action); - localState.setState(nextState); - - if (action == LOCAL_ABORT && currentState != ERROR) { - return abortSession(currentState, localState); - } - - if (nextState == ERROR) { - if (LOG.isLoggable(WARNING)) { - LOG.warning("Error: Invalid action in state " + - currentState.name()); - } - return noUpdate(localState, true); - } - List<BaseMessage> messages; - List<Event> events = Collections.emptyList(); - - if (action == LOCAL_ACCEPT || action == LOCAL_DECLINE) { - BaseMessage msg; - if (action == LOCAL_ACCEPT) { - localState.setTask(TASK_ADD_SHARED_FORUM); - msg = new SimpleMessage(SHARE_MSG_TYPE_ACCEPT, - localState.getGroupId(), localState.getSessionId()); - } else { - localState.setTask( - TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US); - msg = new SimpleMessage(SHARE_MSG_TYPE_DECLINE, - localState.getGroupId(), localState.getSessionId()); - } - messages = Collections.singletonList(msg); - logLocalAction(currentState, localState, msg); - } - else if (action == LOCAL_LEAVE) { - BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE, - localState.getGroupId(), localState.getSessionId()); - messages = Collections.singletonList(msg); - logLocalAction(currentState, localState, msg); - } - else { - throw new IllegalArgumentException("Unknown Local Action"); - } - return new StateUpdate<InviteeSessionState, BaseMessage>(false, - false, localState, messages, events); - } catch (FormatException e) { - throw new IllegalArgumentException(e); - } - } - - @Override - public StateUpdate<InviteeSessionState, BaseMessage> onMessageReceived( - InviteeSessionState localState, BaseMessage msg) { - - try { - State currentState = localState.getState(); - Action action = Action.getRemote(msg.getType()); - State nextState = currentState.next(action); - localState.setState(nextState); - - logMessageReceived(currentState, nextState, msg.getType(), msg); - - if (nextState == ERROR) { - if (currentState != ERROR) { - return abortSession(currentState, localState); - } else { - return noUpdate(localState, true); - } - } - - List<BaseMessage> messages = Collections.emptyList(); - List<Event> events = Collections.emptyList(); - boolean deleteMsg = false; - - if (currentState == LEFT) { - // ignore and delete messages coming in while in that state - deleteMsg = true; - } - // the sharer left the forum she had shared with us - else if (action == REMOTE_LEAVE && currentState == FINISHED) { - localState.setTask(TASK_UNSHARE_FORUM_SHARED_WITH_US); - } - else if (currentState == FINISHED) { - // ignore and delete messages coming in while in that state - // note that LEAVE is possible, but was handled above - deleteMsg = true; - } - // the sharer left the forum before we couldn't even respond - else if (action == REMOTE_LEAVE) { - localState.setTask(TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US); - } - // we have just received our invitation - else if (action == REMOTE_INVITATION) { - Forum forum = forumFactory - .createForum(localState.getForumName(), - localState.getForumSalt()); - localState.setTask(TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US); - ContactId contactId = localState.getContactId(); - Event event = new ForumInvitationReceivedEvent(forum, contactId); - events = Collections.singletonList(event); - } - else { - throw new IllegalArgumentException("Bad state"); - } - return new StateUpdate<InviteeSessionState, BaseMessage>(deleteMsg, - false, localState, messages, events); - } catch (FormatException e) { - throw new IllegalArgumentException(e); - } - } - - private void logLocalAction(State state, - InviteeSessionState localState, BaseMessage msg) { - - if (!LOG.isLoggable(INFO)) return; - - String a = "response"; - if (msg.getType() == SHARE_MSG_TYPE_LEAVE) a = "leave"; - - LOG.info("Sending " + a + " in state " + state.name() + - " with session ID " + - msg.getSessionId().hashCode() + " in group " + - msg.getGroupId().hashCode() + ". " + - "Moving on to state " + localState.getState().name() - ); - } - - private void logMessageReceived(State currentState, State nextState, - long type, BaseMessage msg) { - - if (!LOG.isLoggable(INFO)) return; - - String t = "unknown"; - if (type == SHARE_MSG_TYPE_INVITATION) t = "INVITE"; - else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE"; - else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT"; - - LOG.info("Received " + t + " in state " + currentState.name() + - " with session ID " + - msg.getSessionId().hashCode() + " in group " + - msg.getGroupId().hashCode() + ". " + - "Moving on to state " + nextState.name() - ); - } - - @Override - public StateUpdate<InviteeSessionState, BaseMessage> onMessageDelivered( - InviteeSessionState localState, BaseMessage delivered) { - try { - return noUpdate(localState, false); - } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - return null; - } - } - - private StateUpdate<InviteeSessionState, BaseMessage> abortSession( - State currentState, InviteeSessionState localState) - throws FormatException { - - if (LOG.isLoggable(WARNING)) { - LOG.warning("Aborting protocol session " + - localState.getSessionId().hashCode() + - " in state " + currentState.name()); - } - localState.setState(ERROR); - BaseMessage msg = - new SimpleMessage(SHARE_MSG_TYPE_ABORT, localState.getGroupId(), - localState.getSessionId()); - List<BaseMessage> messages = Collections.singletonList(msg); - - List<Event> events = Collections.emptyList(); - - return new StateUpdate<InviteeSessionState, BaseMessage>(false, false, - localState, messages, events); - } - - private StateUpdate<InviteeSessionState, BaseMessage> noUpdate( - InviteeSessionState localState, boolean delete) throws FormatException { - - return new StateUpdate<InviteeSessionState, BaseMessage>(delete, false, - localState, Collections.<BaseMessage>emptyList(), - Collections.<Event>emptyList()); - } -} diff --git a/briar-core/src/org/briarproject/forum/SharerEngine.java b/briar-core/src/org/briarproject/forum/SharerEngine.java deleted file mode 100644 index 4a142c039523413f5e18d982f51c55e62d3fbf0e..0000000000000000000000000000000000000000 --- a/briar-core/src/org/briarproject/forum/SharerEngine.java +++ /dev/null @@ -1,228 +0,0 @@ -package org.briarproject.forum; - -import org.briarproject.api.FormatException; -import org.briarproject.api.clients.ProtocolEngine; -import org.briarproject.api.contact.ContactId; -import org.briarproject.api.event.Event; -import org.briarproject.api.event.ForumInvitationResponseReceivedEvent; - -import java.util.Collections; -import java.util.List; -import java.util.logging.Logger; - -import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ACCEPT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_DECLINE; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.api.forum.ForumConstants.TASK_ADD_FORUM_TO_LIST_TO_BE_SHARED_BY_US; -import static org.briarproject.api.forum.ForumConstants.TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US; -import static org.briarproject.api.forum.ForumConstants.TASK_SHARE_FORUM; -import static org.briarproject.api.forum.ForumConstants.TASK_UNSHARE_FORUM_SHARED_BY_US; -import static org.briarproject.api.forum.ForumSharingMessage.BaseMessage; -import static org.briarproject.api.forum.ForumSharingMessage.Invitation; -import static org.briarproject.api.forum.ForumSharingMessage.SimpleMessage; -import static org.briarproject.forum.SharerSessionState.Action; -import static org.briarproject.forum.SharerSessionState.Action.LOCAL_ABORT; -import static org.briarproject.forum.SharerSessionState.Action.LOCAL_INVITATION; -import static org.briarproject.forum.SharerSessionState.Action.LOCAL_LEAVE; -import static org.briarproject.forum.SharerSessionState.Action.REMOTE_ACCEPT; -import static org.briarproject.forum.SharerSessionState.Action.REMOTE_DECLINE; -import static org.briarproject.forum.SharerSessionState.Action.REMOTE_LEAVE; -import static org.briarproject.forum.SharerSessionState.State; -import static org.briarproject.forum.SharerSessionState.State.ERROR; -import static org.briarproject.forum.SharerSessionState.State.FINISHED; -import static org.briarproject.forum.SharerSessionState.State.LEFT; - -public class SharerEngine - implements ProtocolEngine<Action, SharerSessionState, BaseMessage> { - - private static final Logger LOG = - Logger.getLogger(SharerEngine.class.getName()); - - @Override - public StateUpdate<SharerSessionState, BaseMessage> onLocalAction( - SharerSessionState localState, Action action) { - - try { - State currentState = localState.getState(); - State nextState = currentState.next(action); - localState.setState(nextState); - - if (action == LOCAL_ABORT && currentState != ERROR) { - return abortSession(currentState, localState); - } - - if (nextState == ERROR) { - if (LOG.isLoggable(WARNING)) { - LOG.warning("Error: Invalid action in state " + - currentState.name()); - } - return noUpdate(localState, true); - } - List<BaseMessage> messages; - List<Event> events = Collections.emptyList(); - - if (action == LOCAL_INVITATION) { - BaseMessage msg = new Invitation(localState.getGroupId(), - localState.getSessionId(), localState.getForumName(), - localState.getForumSalt(), localState.getMessage()); - messages = Collections.singletonList(msg); - logLocalAction(currentState, nextState, msg); - - // remember that we offered to share this forum - localState.setTask(TASK_ADD_FORUM_TO_LIST_TO_BE_SHARED_BY_US); - } - else if (action == LOCAL_LEAVE) { - BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE, - localState.getGroupId(), localState.getSessionId()); - messages = Collections.singletonList(msg); - logLocalAction(currentState, nextState, msg); - } - else { - throw new IllegalArgumentException("Unknown Local Action"); - } - return new StateUpdate<SharerSessionState, BaseMessage>(false, - false, localState, messages, events); - } catch (FormatException e) { - throw new IllegalArgumentException(e); - } - } - - @Override - public StateUpdate<SharerSessionState, BaseMessage> onMessageReceived( - SharerSessionState localState, BaseMessage msg) { - - try { - State currentState = localState.getState(); - Action action = Action.getRemote(msg.getType()); - State nextState = currentState.next(action); - localState.setState(nextState); - - logMessageReceived(currentState, nextState, msg.getType(), msg); - - if (nextState == ERROR) { - if (currentState != ERROR) { - return abortSession(currentState, localState); - } else { - return noUpdate(localState, true); - } - } - List<BaseMessage> messages = Collections.emptyList(); - List<Event> events = Collections.emptyList(); - boolean deleteMsg = false; - - if (currentState == LEFT) { - // ignore and delete messages coming in while in that state - deleteMsg = true; - } - else if (action == REMOTE_LEAVE) { - localState.setTask(TASK_UNSHARE_FORUM_SHARED_BY_US); - } - else if (currentState == FINISHED) { - // ignore and delete messages coming in while in that state - // note that LEAVE is possible, but was handled above - deleteMsg = true; - } - // we have sent our invitation and just got a response - else if (action == REMOTE_ACCEPT || action == REMOTE_DECLINE) { - if (action == REMOTE_ACCEPT) { - localState.setTask(TASK_SHARE_FORUM); - } else { - // this ensures that the forum can be shared again - localState.setTask( - TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US); - } - String name = localState.getForumName(); - ContactId c = localState.getContactId(); - Event event = new ForumInvitationResponseReceivedEvent(name, c); - events = Collections.singletonList(event); - } - else { - throw new IllegalArgumentException("Bad state"); - } - return new StateUpdate<SharerSessionState, BaseMessage>(deleteMsg, - false, localState, messages, events); - } catch (FormatException e) { - throw new IllegalArgumentException(e); - } - } - - private void logLocalAction(State currentState, State nextState, - BaseMessage msg) { - - if (!LOG.isLoggable(INFO)) return; - - String a = "invitation"; - if (msg.getType() == SHARE_MSG_TYPE_LEAVE) a = "leave"; - - LOG.info("Sending " + a + " in state " + currentState.name() + - " with session ID " + - msg.getSessionId().hashCode() + " in group " + - msg.getGroupId().hashCode() + ". " + - "Moving on to state " + nextState.name() - ); - } - - private void logMessageReceived(State currentState, State nextState, - long type, BaseMessage msg) { - - if (!LOG.isLoggable(INFO)) return; - - String t = "unknown"; - if (type == SHARE_MSG_TYPE_ACCEPT) t = "ACCEPT"; - else if (type == SHARE_MSG_TYPE_DECLINE) t = "DECLINE"; - else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE"; - else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT"; - - LOG.info("Received " + t + " in state " + currentState.name() + - " with session ID " + - msg.getSessionId().hashCode() + " in group " + - msg.getGroupId().hashCode() + ". " + - "Moving on to state " + nextState.name() - ); - } - - @Override - public StateUpdate<SharerSessionState, BaseMessage> onMessageDelivered( - SharerSessionState localState, BaseMessage delivered) { - try { - return noUpdate(localState, false); - } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - return null; - } - } - - private StateUpdate<SharerSessionState, BaseMessage> abortSession( - State currentState, SharerSessionState localState) - throws FormatException { - - if (LOG.isLoggable(WARNING)) { - LOG.warning("Aborting protocol session " + - localState.getSessionId().hashCode() + - " in state " + currentState.name()); - } - - localState.setState(ERROR); - BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_ABORT, - localState.getGroupId(), localState.getSessionId()); - List<BaseMessage> messages = Collections.singletonList(msg); - - List<Event> events = Collections.emptyList(); - - return new StateUpdate<SharerSessionState, BaseMessage>(false, false, - localState, messages, events); - } - - private StateUpdate<SharerSessionState, BaseMessage> noUpdate( - SharerSessionState localState, boolean delete) - throws FormatException { - - return new StateUpdate<SharerSessionState, BaseMessage>(delete, false, - localState, Collections.<BaseMessage>emptyList(), - Collections.<Event>emptyList()); - } - -} diff --git a/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java b/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java new file mode 100644 index 0000000000000000000000000000000000000000..7bb3295b7b02a925718b08ca2da3875a25d58980 --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/BlogInviteeSessionState.java @@ -0,0 +1,57 @@ +package org.briarproject.sharing; + +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.MessageId; + +import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME; +import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC; +import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY; +import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE; + +public class BlogInviteeSessionState extends InviteeSessionState { + + private final String blogTitle; + private final String blogDesc; + private final String blogAuthorName; + private final byte[] blogPublicKey; + + public BlogInviteeSessionState(SessionId sessionId, MessageId storageId, + GroupId groupId, State state, ContactId contactId, GroupId blogId, + String blogTitle, String blogDesc, String blogAuthorName, + byte[] blogPublicKey) { + super(sessionId, storageId, groupId, state, contactId, blogId); + + this.blogTitle = blogTitle; + this.blogDesc = blogDesc; + this.blogAuthorName = blogAuthorName; + this.blogPublicKey = blogPublicKey; + } + + public BdfDictionary toBdfDictionary() { + BdfDictionary d = super.toBdfDictionary(); + d.put(BLOG_TITLE, getBlogTitle()); + d.put(BLOG_DESC, getBlogDesc()); + d.put(BLOG_AUTHOR_NAME, getBlogAuthorName()); + d.put(BLOG_PUBLIC_KEY, getBlogPublicKey()); + return d; + } + + public String getBlogTitle() { + return blogTitle; + } + + public String getBlogDesc() { + return blogDesc; + } + + public String getBlogAuthorName() { + return blogAuthorName; + } + + public byte[] getBlogPublicKey() { + return blogPublicKey; + } +} diff --git a/briar-core/src/org/briarproject/sharing/BlogSharerSessionState.java b/briar-core/src/org/briarproject/sharing/BlogSharerSessionState.java new file mode 100644 index 0000000000000000000000000000000000000000..16ef1355b2183ab4d45c7074fef9e4b5c37b5e41 --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/BlogSharerSessionState.java @@ -0,0 +1,57 @@ +package org.briarproject.sharing; + +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.MessageId; + +import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME; +import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC; +import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY; +import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE; + +public class BlogSharerSessionState extends SharerSessionState { + + private final String blogTitle; + private final String blogDesc; + private final String blogAuthorName; + private final byte[] blogPublicKey; + + public BlogSharerSessionState(SessionId sessionId, MessageId storageId, + GroupId groupId, State state, ContactId contactId, GroupId blogId, + String blogTitle, String blogDesc, String blogAuthorName, + byte[] blogPublicKey) { + super(sessionId, storageId, groupId, state, contactId, blogId); + + this.blogTitle = blogTitle; + this.blogDesc = blogDesc; + this.blogAuthorName = blogAuthorName; + this.blogPublicKey = blogPublicKey; + } + + public BdfDictionary toBdfDictionary() { + BdfDictionary d = super.toBdfDictionary(); + d.put(BLOG_TITLE, getBlogTitle()); + d.put(BLOG_DESC, getBlogDesc()); + d.put(BLOG_AUTHOR_NAME, getBlogAuthorName()); + d.put(BLOG_PUBLIC_KEY, getBlogPublicKey()); + return d; + } + + public String getBlogTitle() { + return blogTitle; + } + + public String getBlogDesc() { + return blogDesc; + } + + public String getBlogAuthorName() { + return blogAuthorName; + } + + public byte[] getBlogPublicKey() { + return blogPublicKey; + } +} diff --git a/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..ba67ff635ee898c342994773cf8f5b4dd9787160 --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java @@ -0,0 +1,293 @@ +package org.briarproject.sharing; + +import org.briarproject.api.FormatException; +import org.briarproject.api.blogs.Blog; +import org.briarproject.api.blogs.BlogFactory; +import org.briarproject.api.blogs.BlogInvitationMessage; +import org.briarproject.api.blogs.BlogManager; +import org.briarproject.api.blogs.BlogSharingManager; +import org.briarproject.api.blogs.BlogSharingMessage.BlogInvitation; +import org.briarproject.api.clients.ClientHelper; +import org.briarproject.api.clients.MessageQueueManager; +import org.briarproject.api.clients.PrivateGroupFactory; +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.data.BdfList; +import org.briarproject.api.data.MetadataEncoder; +import org.briarproject.api.data.MetadataParser; +import org.briarproject.api.db.DatabaseComponent; +import org.briarproject.api.db.DbException; +import org.briarproject.api.db.Transaction; +import org.briarproject.api.event.BlogInvitationReceivedEvent; +import org.briarproject.api.event.BlogInvitationResponseReceivedEvent; +import org.briarproject.api.identity.Author; +import org.briarproject.api.identity.AuthorFactory; +import org.briarproject.api.sync.ClientId; +import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.MessageId; +import org.briarproject.api.system.Clock; +import org.briarproject.util.StringUtils; + +import java.security.SecureRandom; + +import javax.inject.Inject; + +import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME; +import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC; +import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY; +import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE; + +class BlogSharingManagerImpl extends + SharingManagerImpl<Blog, BlogInvitation, BlogInvitationMessage, BlogInviteeSessionState, BlogSharerSessionState, BlogInvitationReceivedEvent, BlogInvitationResponseReceivedEvent> + implements BlogSharingManager { + + static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString( + "bee438b5de0b3a685badc4e49d76e72d" + + "21e01c4b569a775112756bdae267a028")); + + private final BlogManager blogManager; + + private final SFactory sFactory; + private final IFactory iFactory; + private final ISFactory isFactory; + private final SSFactory ssFactory; + private final IRFactory irFactory; + private final IRRFactory irrFactory; + + @Inject + BlogSharingManagerImpl(AuthorFactory authorFactory, BlogFactory blogFactory, + BlogManager blogManager, ClientHelper clientHelper, Clock clock, + DatabaseComponent db, MessageQueueManager messageQueueManager, + MetadataEncoder metadataEncoder, MetadataParser metadataParser, + PrivateGroupFactory privateGroupFactory, SecureRandom random) { + + super(db, messageQueueManager, clientHelper, metadataParser, + metadataEncoder, random, privateGroupFactory, clock); + this.blogManager = blogManager; + + sFactory = new SFactory(authorFactory, blogFactory, blogManager); + iFactory = new IFactory(); + isFactory = new ISFactory(); + ssFactory = new SSFactory(); + irFactory = new IRFactory(sFactory); + irrFactory = new IRRFactory(); + } + + @Override + public ClientId getClientId() { + return CLIENT_ID; + } + + @Override + protected ClientId getShareableClientId() { + return blogManager.getClientId(); + } + + @Override + protected BlogInvitationMessage createInvitationMessage(MessageId id, + BlogInvitation msg, ContactId contactId, boolean available, + long time, boolean local, boolean sent, boolean seen, + boolean read) { + return new BlogInvitationMessage(id, msg.getSessionId(), contactId, + msg.getBlogTitle(), msg.getMessage(), available, time, local, + sent, seen, read); + } + + @Override + protected ShareableFactory<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState> getSFactory() { + return sFactory; + } + + @Override + protected InvitationFactory<BlogInvitation, BlogSharerSessionState> getIFactory() { + return iFactory; + } + + @Override + protected InviteeSessionStateFactory<Blog, BlogInviteeSessionState> getISFactory() { + return isFactory; + } + + @Override + protected SharerSessionStateFactory<Blog, BlogSharerSessionState> getSSFactory() { + return ssFactory; + } + + @Override + protected InvitationReceivedEventFactory<BlogInviteeSessionState, BlogInvitationReceivedEvent> getIRFactory() { + return irFactory; + } + + @Override + protected InvitationResponseReceivedEventFactory<BlogSharerSessionState, BlogInvitationResponseReceivedEvent> getIRRFactory() { + return irrFactory; + } + + static class SFactory implements + ShareableFactory<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState> { + + private final AuthorFactory authorFactory; + private final BlogFactory blogFactory; + private final BlogManager blogManager; + + SFactory(AuthorFactory authorFactory, BlogFactory BlogFactory, + BlogManager BlogManager) { + this.authorFactory = authorFactory; + this.blogFactory = BlogFactory; + this.blogManager = BlogManager; + } + + @Override + public BdfList encode(Blog f) { + return BdfList.of(f.getName(), f.getDescription(), + BdfList.of(f.getAuthor().getName(), + f.getAuthor().getPublicKey())); + } + + @Override + public Blog get(Transaction txn, GroupId groupId) + throws DbException { + return blogManager.getBlog(txn, groupId); + } + + @Override + public Blog parse(BdfList shareable) throws FormatException { + Author author = authorFactory + .createAuthor(shareable.getList(2).getString(0), + shareable.getList(2).getRaw(1)); + return blogFactory + .createBlog(shareable.getString(0), shareable.getString(1), + author); + } + + @Override + public Blog parse(BlogInvitation msg) { + Author author = authorFactory.createAuthor(msg.getBlogAuthorName(), + msg.getBlogPublicKey()); + return blogFactory + .createBlog(msg.getBlogTitle(), msg.getBlogDesc(), author); + } + + public Blog parse(BlogInviteeSessionState state) { + Author author = authorFactory + .createAuthor(state.getBlogAuthorName(), + state.getBlogPublicKey()); + return blogFactory + .createBlog(state.getBlogTitle(), state.getBlogDesc(), + author); + } + + @Override + public Blog parse(BlogSharerSessionState state) { + Author author = authorFactory + .createAuthor(state.getBlogAuthorName(), + state.getBlogPublicKey()); + return blogFactory + .createBlog(state.getBlogTitle(), state.getBlogDesc(), + author); + } + } + + static class IFactory implements + InvitationFactory<BlogInvitation, BlogSharerSessionState> { + @Override + public BlogInvitation build(GroupId groupId, BdfDictionary d) + throws FormatException { + return BlogInvitation.from(groupId, d); + } + + @Override + public BlogInvitation build(BlogSharerSessionState localState) { + return new BlogInvitation(localState.getGroupId(), + localState.getSessionId(), localState.getBlogTitle(), + localState.getBlogDesc(), localState.getBlogAuthorName(), + localState.getBlogPublicKey(), localState.getMessage()); + } + } + + static class ISFactory implements + InviteeSessionStateFactory<Blog, BlogInviteeSessionState> { + @Override + public BlogInviteeSessionState build(SessionId sessionId, + MessageId storageId, GroupId groupId, + InviteeSessionState.State state, ContactId contactId, + GroupId blogId, BdfDictionary d) throws FormatException { + String blogTitle = d.getString(BLOG_TITLE); + String blogDesc = d.getString(BLOG_DESC); + String blogAuthorName = d.getString(BLOG_AUTHOR_NAME); + byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY); + return new BlogInviteeSessionState(sessionId, storageId, + groupId, state, contactId, blogId, blogTitle, blogDesc, + blogAuthorName, blogPublicKey); + } + + @Override + public BlogInviteeSessionState build(SessionId sessionId, + MessageId storageId, GroupId groupId, + InviteeSessionState.State state, ContactId contactId, + Blog blog) { + return new BlogInviteeSessionState(sessionId, storageId, + groupId, state, contactId, blog.getId(), blog.getName(), + blog.getDescription(), blog.getAuthor().getName(), + blog.getAuthor().getPublicKey()); + } + } + + static class SSFactory implements + SharerSessionStateFactory<Blog, BlogSharerSessionState> { + @Override + public BlogSharerSessionState build(SessionId sessionId, + MessageId storageId, GroupId groupId, + SharerSessionState.State state, ContactId contactId, + GroupId blogId, BdfDictionary d) throws FormatException { + String blogTitle = d.getString(BLOG_TITLE); + String blogDesc = d.getString(BLOG_DESC); + String blogAuthorName = d.getString(BLOG_AUTHOR_NAME); + byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY); + return new BlogSharerSessionState(sessionId, storageId, + groupId, state, contactId, blogId, blogTitle, blogDesc, + blogAuthorName, blogPublicKey); + } + + @Override + public BlogSharerSessionState build(SessionId sessionId, + MessageId storageId, GroupId groupId, + SharerSessionState.State state, ContactId contactId, + Blog blog) { + return new BlogSharerSessionState(sessionId, storageId, + groupId, state, contactId, blog.getId(), blog.getName(), + blog.getDescription(), blog.getAuthor().getName(), + blog.getAuthor().getPublicKey()); + } + } + + static class IRFactory implements + InvitationReceivedEventFactory<BlogInviteeSessionState, BlogInvitationReceivedEvent> { + + private final SFactory sFactory; + + IRFactory(SFactory sFactory) { + this.sFactory = sFactory; + } + + @Override + public BlogInvitationReceivedEvent build( + BlogInviteeSessionState localState) { + Blog blog = sFactory.parse(localState); + ContactId contactId = localState.getContactId(); + return new BlogInvitationReceivedEvent(blog, contactId); + } + } + + static class IRRFactory implements + InvitationResponseReceivedEventFactory<BlogSharerSessionState, BlogInvitationResponseReceivedEvent> { + @Override + public BlogInvitationResponseReceivedEvent build( + BlogSharerSessionState localState) { + String title = localState.getBlogTitle(); + ContactId c = localState.getContactId(); + return new BlogInvitationResponseReceivedEvent(title, c); + } + } +} diff --git a/briar-core/src/org/briarproject/sharing/BlogSharingValidator.java b/briar-core/src/org/briarproject/sharing/BlogSharingValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..26b89bb52c512c118e02ea5075226e42b5829eda --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/BlogSharingValidator.java @@ -0,0 +1,98 @@ +package org.briarproject.sharing; + +import org.briarproject.api.FormatException; +import org.briarproject.api.clients.BdfMessageContext; +import org.briarproject.api.clients.ClientHelper; +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.data.BdfList; +import org.briarproject.api.data.MetadataEncoder; +import org.briarproject.api.sync.Group; +import org.briarproject.api.sync.Message; +import org.briarproject.api.system.Clock; +import org.briarproject.clients.BdfMessageValidator; + +import javax.inject.Inject; + +import static org.briarproject.api.blogs.BlogConstants.BLOG_AUTHOR_NAME; +import static org.briarproject.api.blogs.BlogConstants.BLOG_DESC; +import static org.briarproject.api.blogs.BlogConstants.BLOG_TITLE; +import static org.briarproject.api.blogs.BlogConstants.BLOG_PUBLIC_KEY; +import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_DESC_LENGTH; +import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_TITLE_LENGTH; +import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; +import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; +import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG; +import static org.briarproject.api.sharing.SharingConstants.LOCAL; +import static org.briarproject.api.sharing.SharingConstants.SESSION_ID; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; +import static org.briarproject.api.sharing.SharingConstants.TIME; +import static org.briarproject.api.sharing.SharingConstants.TYPE; +import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; + +class BlogSharingValidator extends BdfMessageValidator { + + @Inject + BlogSharingValidator(ClientHelper clientHelper, + MetadataEncoder metadataEncoder, Clock clock) { + super(clientHelper, metadataEncoder, clock); + } + + @Override + protected BdfMessageContext validateMessage(Message m, Group g, + BdfList body) throws FormatException { + + BdfDictionary d = new BdfDictionary(); + long type = body.getLong(0); + byte[] id = body.getRaw(1); + checkLength(id, SessionId.LENGTH); + + if (type == SHARE_MSG_TYPE_INVITATION) { + checkSize(body, 5, 6); + + String name = body.getString(2); + checkLength(name, 1, MAX_BLOG_TITLE_LENGTH); + + String desc = body.getString(3); + checkLength(desc, 1, MAX_BLOG_DESC_LENGTH); + + BdfList author = body.getList(4); + checkSize(author, 2); + + String authorName = author.getString(0); + checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH); + + byte[] publicKey = author.getRaw(1); + checkLength(publicKey, 1, MAX_PUBLIC_KEY_LENGTH); + + d.put(BLOG_TITLE, name); + d.put(BLOG_DESC, desc); + d.put(BLOG_AUTHOR_NAME, authorName); + d.put(BLOG_PUBLIC_KEY, publicKey); + + if (body.size() > 5) { + String msg = body.getString(5); + checkLength(msg, 0, MAX_MESSAGE_BODY_LENGTH); + d.put(INVITATION_MSG, msg); + } + } else { + checkSize(body, 2); + if (type != SHARE_MSG_TYPE_ACCEPT && + type != SHARE_MSG_TYPE_DECLINE && + type != SHARE_MSG_TYPE_LEAVE && + type != SHARE_MSG_TYPE_ABORT) { + throw new FormatException(); + } + } + // Return the metadata + d.put(TYPE, type); + d.put(SESSION_ID, id); + d.put(LOCAL, false); + d.put(TIME, m.getTimestamp()); + return new BdfMessageContext(d); + } +} diff --git a/briar-core/src/org/briarproject/sharing/ForumInviteeSessionState.java b/briar-core/src/org/briarproject/sharing/ForumInviteeSessionState.java new file mode 100644 index 0000000000000000000000000000000000000000..f8ac1629b121deef1f45dd777af78df2b920e9ea --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/ForumInviteeSessionState.java @@ -0,0 +1,40 @@ +package org.briarproject.sharing; + +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.MessageId; + +import static org.briarproject.api.forum.ForumConstants.FORUM_NAME; +import static org.briarproject.api.forum.ForumConstants.FORUM_SALT; + +public class ForumInviteeSessionState extends InviteeSessionState { + + private final String forumName; + private final byte[] forumSalt; + + public ForumInviteeSessionState(SessionId sessionId, MessageId storageId, + GroupId groupId, State state, ContactId contactId, GroupId forumId, + String forumName, byte[] forumSalt) { + super(sessionId, storageId, groupId, state, contactId, forumId); + + this.forumName = forumName; + this.forumSalt = forumSalt; + } + + public BdfDictionary toBdfDictionary() { + BdfDictionary d = super.toBdfDictionary(); + d.put(FORUM_NAME, getForumName()); + d.put(FORUM_SALT, getForumSalt()); + return d; + } + + public String getForumName() { + return forumName; + } + + public byte[] getForumSalt() { + return forumSalt; + } +} diff --git a/briar-core/src/org/briarproject/sharing/ForumSharerSessionState.java b/briar-core/src/org/briarproject/sharing/ForumSharerSessionState.java new file mode 100644 index 0000000000000000000000000000000000000000..cfc0c231c7f90fe53ac5c90232417867a1288706 --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/ForumSharerSessionState.java @@ -0,0 +1,40 @@ +package org.briarproject.sharing; + +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.MessageId; + +import static org.briarproject.api.forum.ForumConstants.FORUM_NAME; +import static org.briarproject.api.forum.ForumConstants.FORUM_SALT; + +public class ForumSharerSessionState extends SharerSessionState { + + private final String forumName; + private final byte[] forumSalt; + + public ForumSharerSessionState(SessionId sessionId, MessageId storageId, + GroupId groupId, State state, ContactId contactId, GroupId forumId, + String forumName, byte[] forumSalt) { + super(sessionId, storageId, groupId, state, contactId, forumId); + + this.forumName = forumName; + this.forumSalt = forumSalt; + } + + public BdfDictionary toBdfDictionary() { + BdfDictionary d = super.toBdfDictionary(); + d.put(FORUM_NAME, getForumName()); + d.put(FORUM_SALT, getForumSalt()); + return d; + } + + public String getForumName() { + return forumName; + } + + public byte[] getForumSalt() { + return forumSalt; + } +} diff --git a/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..eb06dff4ca6ade66985921d35bce2169bb64c56c --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/ForumSharingManagerImpl.java @@ -0,0 +1,269 @@ +package org.briarproject.sharing; + +import org.briarproject.api.FormatException; +import org.briarproject.api.clients.ClientHelper; +import org.briarproject.api.clients.MessageQueueManager; +import org.briarproject.api.clients.PrivateGroupFactory; +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.data.BdfList; +import org.briarproject.api.data.MetadataEncoder; +import org.briarproject.api.data.MetadataParser; +import org.briarproject.api.db.DatabaseComponent; +import org.briarproject.api.db.DbException; +import org.briarproject.api.db.Transaction; +import org.briarproject.api.event.ForumInvitationReceivedEvent; +import org.briarproject.api.event.ForumInvitationResponseReceivedEvent; +import org.briarproject.api.forum.Forum; +import org.briarproject.api.forum.ForumFactory; +import org.briarproject.api.forum.ForumInvitationMessage; +import org.briarproject.api.forum.ForumManager; +import org.briarproject.api.forum.ForumSharingManager; +import org.briarproject.api.forum.ForumSharingMessage.ForumInvitation; +import org.briarproject.api.sync.ClientId; +import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.MessageId; +import org.briarproject.api.system.Clock; +import org.briarproject.util.StringUtils; + +import java.security.SecureRandom; + +import javax.inject.Inject; + +import static org.briarproject.api.forum.ForumConstants.FORUM_NAME; +import static org.briarproject.api.forum.ForumConstants.FORUM_SALT; + +class ForumSharingManagerImpl extends + SharingManagerImpl<Forum, ForumInvitation, ForumInvitationMessage, ForumInviteeSessionState, ForumSharerSessionState, ForumInvitationReceivedEvent, ForumInvitationResponseReceivedEvent> + implements ForumSharingManager, ForumManager.RemoveForumHook { + + static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString( + "cd11a5d04dccd9e2931d6fc3df456313" + + "63bb3e9d9d0e9405fccdb051f41f5449")); + + private final ForumManager forumManager; + + private final SFactory sFactory; + private final IFactory iFactory; + private final ISFactory isFactory; + private final SSFactory ssFactory; + private final IRFactory irFactory; + private final IRRFactory irrFactory; + + @Inject + ForumSharingManagerImpl(ClientHelper clientHelper, + Clock clock, DatabaseComponent db, + ForumFactory forumFactory, + ForumManager forumManager, + MessageQueueManager messageQueueManager, + MetadataEncoder metadataEncoder, + MetadataParser metadataParser, + PrivateGroupFactory privateGroupFactory, + SecureRandom random) { + super(db, messageQueueManager, clientHelper, metadataParser, + metadataEncoder, random, privateGroupFactory, clock); + this.forumManager = forumManager; + + sFactory = new SFactory(forumFactory, forumManager); + iFactory = new IFactory(); + isFactory = new ISFactory(); + ssFactory = new SSFactory(); + irFactory = new IRFactory(sFactory); + irrFactory = new IRRFactory(); + } + + @Override + public ClientId getClientId() { + return CLIENT_ID; + } + + @Override + protected ClientId getShareableClientId() { + return forumManager.getClientId(); + } + + @Override + protected ForumInvitationMessage createInvitationMessage(MessageId id, + ForumInvitation msg, ContactId contactId, boolean available, + long time, boolean local, boolean sent, boolean seen, + boolean read) { + return new ForumInvitationMessage(id, msg.getSessionId(), contactId, + msg.getForumName(), msg.getMessage(), available, time, local, + sent, seen, read); + } + + @Override + protected ShareableFactory<Forum, ForumInvitation, ForumInviteeSessionState, ForumSharerSessionState> getSFactory() { + return sFactory; + } + + @Override + protected InvitationFactory<ForumInvitation, ForumSharerSessionState> getIFactory() { + return iFactory; + } + + @Override + protected InviteeSessionStateFactory<Forum, ForumInviteeSessionState> getISFactory() { + return isFactory; + } + + @Override + protected SharerSessionStateFactory<Forum, ForumSharerSessionState> getSSFactory() { + return ssFactory; + } + + @Override + protected InvitationReceivedEventFactory<ForumInviteeSessionState, ForumInvitationReceivedEvent> getIRFactory() { + return irFactory; + } + + @Override + protected InvitationResponseReceivedEventFactory<ForumSharerSessionState, ForumInvitationResponseReceivedEvent> getIRRFactory() { + return irrFactory; + } + + @Override + public void removingForum(Transaction txn, Forum f) throws DbException { + removingShareable(txn, f); + } + + static class SFactory implements + ShareableFactory<Forum, ForumInvitation, ForumInviteeSessionState, ForumSharerSessionState> { + + private final ForumFactory forumFactory; + private final ForumManager forumManager; + + SFactory(ForumFactory forumFactory, ForumManager forumManager) { + this.forumFactory = forumFactory; + this.forumManager = forumManager; + } + + @Override + public BdfList encode(Forum f) { + return BdfList.of(f.getName(), f.getSalt()); + } + + @Override + public Forum get(Transaction txn, GroupId groupId) + throws DbException { + return forumManager.getForum(txn, groupId); + } + + @Override + public Forum parse(BdfList shareable) throws FormatException { + return forumFactory + .createForum(shareable.getString(0), shareable.getRaw(1)); + } + + @Override + public Forum parse(ForumInvitation msg) { + return forumFactory + .createForum(msg.getForumName(), msg.getForumSalt()); + } + + public Forum parse(ForumInviteeSessionState state) { + return forumFactory + .createForum(state.getForumName(), state.getForumSalt()); + } + + @Override + public Forum parse(ForumSharerSessionState state) { + return forumFactory + .createForum(state.getForumName(), state.getForumSalt()); + } + } + + static class IFactory implements + InvitationFactory<ForumInvitation, ForumSharerSessionState> { + @Override + public ForumInvitation build(GroupId groupId, BdfDictionary d) + throws FormatException { + return ForumInvitation.from(groupId, d); + } + + @Override + public ForumInvitation build(ForumSharerSessionState localState) { + return new ForumInvitation(localState.getGroupId(), + localState.getSessionId(), localState.getForumName(), + localState.getForumSalt(), localState.getMessage()); + } + } + + static class ISFactory implements + InviteeSessionStateFactory<Forum, ForumInviteeSessionState> { + @Override + public ForumInviteeSessionState build(SessionId sessionId, + MessageId storageId, GroupId groupId, + InviteeSessionState.State state, ContactId contactId, + GroupId forumId, BdfDictionary d) throws FormatException { + String forumName = d.getString(FORUM_NAME); + byte[] forumSalt = d.getRaw(FORUM_SALT); + return new ForumInviteeSessionState(sessionId, storageId, + groupId, state, contactId, forumId, forumName, forumSalt); + } + + @Override + public ForumInviteeSessionState build(SessionId sessionId, + MessageId storageId, GroupId groupId, + InviteeSessionState.State state, ContactId contactId, + Forum forum) { + return new ForumInviteeSessionState(sessionId, storageId, + groupId, state, contactId, forum.getId(), forum.getName(), + forum.getSalt()); + } + } + + static class SSFactory implements + SharerSessionStateFactory<Forum, ForumSharerSessionState> { + @Override + public ForumSharerSessionState build(SessionId sessionId, + MessageId storageId, GroupId groupId, + SharerSessionState.State state, ContactId contactId, + GroupId forumId, BdfDictionary d) throws FormatException { + String forumName = d.getString(FORUM_NAME); + byte[] forumSalt = d.getRaw(FORUM_SALT); + return new ForumSharerSessionState(sessionId, storageId, + groupId, state, contactId, forumId, forumName, forumSalt); + } + + @Override + public ForumSharerSessionState build(SessionId sessionId, + MessageId storageId, GroupId groupId, + SharerSessionState.State state, ContactId contactId, + Forum forum) { + return new ForumSharerSessionState(sessionId, storageId, + groupId, state, contactId, forum.getId(), forum.getName(), + forum.getSalt()); + } + } + + static class IRFactory implements + InvitationReceivedEventFactory<ForumInviteeSessionState, ForumInvitationReceivedEvent> { + + private final SFactory sFactory; + + IRFactory(SFactory sFactory) { + this.sFactory = sFactory; + } + + @Override + public ForumInvitationReceivedEvent build( + ForumInviteeSessionState localState) { + Forum forum = sFactory.parse(localState); + ContactId contactId = localState.getContactId(); + return new ForumInvitationReceivedEvent(forum, contactId); + } + } + + static class IRRFactory implements + InvitationResponseReceivedEventFactory<ForumSharerSessionState, ForumInvitationResponseReceivedEvent> { + @Override + public ForumInvitationResponseReceivedEvent build( + ForumSharerSessionState localState) { + String name = localState.getForumName(); + ContactId c = localState.getContactId(); + return new ForumInvitationResponseReceivedEvent(name, c); + } + } +} diff --git a/briar-core/src/org/briarproject/forum/ForumSharingValidator.java b/briar-core/src/org/briarproject/sharing/ForumSharingValidator.java similarity index 72% rename from briar-core/src/org/briarproject/forum/ForumSharingValidator.java rename to briar-core/src/org/briarproject/sharing/ForumSharingValidator.java index 5009588869a5b4c49a9242809a5a9a340e28c4a3..702466bea05df11eb5887b354b41891ea25f4d80 100644 --- a/briar-core/src/org/briarproject/forum/ForumSharingValidator.java +++ b/briar-core/src/org/briarproject/sharing/ForumSharingValidator.java @@ -1,4 +1,4 @@ -package org.briarproject.forum; +package org.briarproject.sharing; import org.briarproject.api.FormatException; import org.briarproject.api.clients.ClientHelper; @@ -12,25 +12,27 @@ import org.briarproject.api.sync.Message; import org.briarproject.api.system.Clock; import org.briarproject.clients.BdfMessageValidator; +import javax.inject.Inject; + import static org.briarproject.api.forum.ForumConstants.FORUM_NAME; import static org.briarproject.api.forum.ForumConstants.FORUM_SALT; import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH; -import static org.briarproject.api.forum.ForumConstants.GROUP_ID; -import static org.briarproject.api.forum.ForumConstants.INVITATION_MSG; -import static org.briarproject.api.forum.ForumConstants.LOCAL; import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH; -import static org.briarproject.api.forum.ForumConstants.SESSION_ID; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ACCEPT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_DECLINE; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_INVITATION; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.api.forum.ForumConstants.TIME; -import static org.briarproject.api.forum.ForumConstants.TYPE; +import static org.briarproject.api.sharing.SharingConstants.INVITATION_MSG; +import static org.briarproject.api.sharing.SharingConstants.LOCAL; +import static org.briarproject.api.sharing.SharingConstants.SESSION_ID; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; +import static org.briarproject.api.sharing.SharingConstants.TIME; +import static org.briarproject.api.sharing.SharingConstants.TYPE; import static org.briarproject.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; class ForumSharingValidator extends BdfMessageValidator { + @Inject ForumSharingValidator(ClientHelper clientHelper, MetadataEncoder metadataEncoder, Clock clock) { super(clientHelper, metadataEncoder, clock); diff --git a/briar-core/src/org/briarproject/sharing/InvitationFactory.java b/briar-core/src/org/briarproject/sharing/InvitationFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..be82501e8f0c8d1e360eea579f3c75f45d1836d5 --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/InvitationFactory.java @@ -0,0 +1,9 @@ +package org.briarproject.sharing; + +import org.briarproject.api.sharing.SharingMessage; + +public interface InvitationFactory<I extends SharingMessage.Invitation, SS extends SharerSessionState> extends + org.briarproject.api.sharing.InvitationFactory<I> { + + I build(SS localState); +} diff --git a/briar-core/src/org/briarproject/sharing/InvitationReceivedEventFactory.java b/briar-core/src/org/briarproject/sharing/InvitationReceivedEventFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..bdedeee488b931c38605c306290a21d2adce1608 --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/InvitationReceivedEventFactory.java @@ -0,0 +1,8 @@ +package org.briarproject.sharing; + +import org.briarproject.api.event.InvitationReceivedEvent; + +public interface InvitationReceivedEventFactory<IS extends InviteeSessionState, IR extends InvitationReceivedEvent> { + + IR build(IS localState); +} diff --git a/briar-core/src/org/briarproject/sharing/InvitationResponseReceivedEventFactory.java b/briar-core/src/org/briarproject/sharing/InvitationResponseReceivedEventFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..4420f30edd003c2727e162649fa218943a99cf91 --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/InvitationResponseReceivedEventFactory.java @@ -0,0 +1,8 @@ +package org.briarproject.sharing; + +import org.briarproject.api.event.InvitationResponseReceivedEvent; + +public interface InvitationResponseReceivedEventFactory<SS extends SharerSessionState, IRR extends InvitationResponseReceivedEvent> { + + IRR build(SS localState); +} diff --git a/briar-core/src/org/briarproject/sharing/InviteeEngine.java b/briar-core/src/org/briarproject/sharing/InviteeEngine.java new file mode 100644 index 0000000000000000000000000000000000000000..e786d9a74b59891c20c4a79cb9dce856542698d5 --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/InviteeEngine.java @@ -0,0 +1,222 @@ +package org.briarproject.sharing; + +import org.briarproject.api.FormatException; +import org.briarproject.api.clients.ProtocolEngine; +import org.briarproject.api.event.Event; +import org.briarproject.api.event.InvitationReceivedEvent; + +import java.util.Collections; +import java.util.List; +import java.util.logging.Logger; + +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; +import static org.briarproject.api.sharing.SharingConstants.TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US; +import static org.briarproject.api.sharing.SharingConstants.TASK_ADD_SHARED_SHAREABLE; +import static org.briarproject.api.sharing.SharingConstants.TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US; +import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_WITH_US; +import static org.briarproject.api.sharing.SharingMessage.BaseMessage; +import static org.briarproject.api.sharing.SharingMessage.SimpleMessage; + +public class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationReceivedEvent> + implements ProtocolEngine<InviteeSessionState.Action, IS, BaseMessage> { + + private static final Logger LOG = + Logger.getLogger(InviteeEngine.class.getName()); + + private final InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory; + + InviteeEngine(InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory) { + this.invitationReceivedEventFactory = invitationReceivedEventFactory; + } + + @Override + public StateUpdate<IS, BaseMessage> onLocalAction( + IS localState, InviteeSessionState.Action action) { + + try { + InviteeSessionState.State currentState = localState.getState(); + InviteeSessionState.State nextState = currentState.next(action); + localState.setState(nextState); + + if (action == InviteeSessionState.Action.LOCAL_ABORT && currentState != InviteeSessionState.State.ERROR) { + return abortSession(currentState, localState); + } + + if (nextState == InviteeSessionState.State.ERROR) { + if (LOG.isLoggable(WARNING)) { + LOG.warning("Error: Invalid action in state " + + currentState.name()); + } + return noUpdate(localState, true); + } + List<BaseMessage> messages; + List<Event> events = Collections.emptyList(); + + if (action == InviteeSessionState.Action.LOCAL_ACCEPT || action == InviteeSessionState.Action.LOCAL_DECLINE) { + BaseMessage msg; + if (action == InviteeSessionState.Action.LOCAL_ACCEPT) { + localState.setTask(TASK_ADD_SHARED_SHAREABLE); + msg = new SimpleMessage(SHARE_MSG_TYPE_ACCEPT, + localState.getGroupId(), localState.getSessionId()); + } else { + localState.setTask( + TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US); + msg = new SimpleMessage(SHARE_MSG_TYPE_DECLINE, + localState.getGroupId(), localState.getSessionId()); + } + messages = Collections.singletonList(msg); + logLocalAction(currentState, localState, msg); + } + else if (action == InviteeSessionState.Action.LOCAL_LEAVE) { + BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE, + localState.getGroupId(), localState.getSessionId()); + messages = Collections.singletonList(msg); + logLocalAction(currentState, localState, msg); + } + else { + throw new IllegalArgumentException("Unknown Local Action"); + } + return new StateUpdate<IS, BaseMessage>(false, + false, localState, messages, events); + } catch (FormatException e) { + throw new IllegalArgumentException(e); + } + } + + @Override + public StateUpdate<IS, BaseMessage> onMessageReceived( + IS localState, BaseMessage msg) { + + try { + InviteeSessionState.State currentState = localState.getState(); + InviteeSessionState.Action action = InviteeSessionState.Action.getRemote(msg.getType()); + InviteeSessionState.State nextState = currentState.next(action); + localState.setState(nextState); + + logMessageReceived(currentState, nextState, msg.getType(), msg); + + if (nextState == InviteeSessionState.State.ERROR) { + if (currentState != InviteeSessionState.State.ERROR) { + return abortSession(currentState, localState); + } else { + return noUpdate(localState, true); + } + } + + List<BaseMessage> messages = Collections.emptyList(); + List<Event> events = Collections.emptyList(); + boolean deleteMsg = false; + + if (currentState == InviteeSessionState.State.LEFT) { + // ignore and delete messages coming in while in that state + deleteMsg = true; + } + // the sharer left the forum she had shared with us + else if (action == InviteeSessionState.Action.REMOTE_LEAVE && currentState == InviteeSessionState.State.FINISHED) { + localState.setTask(TASK_UNSHARE_SHAREABLE_SHARED_WITH_US); + } + else if (currentState == InviteeSessionState.State.FINISHED) { + // ignore and delete messages coming in while in that state + // note that LEAVE is possible, but was handled above + deleteMsg = true; + } + // the sharer left the forum before we couldn't even respond + else if (action == InviteeSessionState.Action.REMOTE_LEAVE) { + localState.setTask(TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US); + } + // we have just received our invitation + else if (action == InviteeSessionState.Action.REMOTE_INVITATION) { + localState.setTask(TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US); + Event event = invitationReceivedEventFactory.build(localState); + events = Collections.singletonList(event); + } + else { + throw new IllegalArgumentException("Bad state"); + } + return new StateUpdate<IS, BaseMessage>(deleteMsg, + false, localState, messages, events); + } catch (FormatException e) { + throw new IllegalArgumentException(e); + } + } + + private void logLocalAction(InviteeSessionState.State state, + InviteeSessionState localState, BaseMessage msg) { + + if (!LOG.isLoggable(INFO)) return; + + String a = "response"; + if (msg.getType() == SHARE_MSG_TYPE_LEAVE) a = "leave"; + + LOG.info("Sending " + a + " in state " + state.name() + + " with session ID " + + msg.getSessionId().hashCode() + " in group " + + msg.getGroupId().hashCode() + ". " + + "Moving on to state " + localState.getState().name() + ); + } + + private void logMessageReceived(InviteeSessionState.State currentState, InviteeSessionState.State nextState, + long type, BaseMessage msg) { + + if (!LOG.isLoggable(INFO)) return; + + String t = "unknown"; + if (type == SHARE_MSG_TYPE_INVITATION) t = "INVITE"; + else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE"; + else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT"; + + LOG.info("Received " + t + " in state " + currentState.name() + + " with session ID " + + msg.getSessionId().hashCode() + " in group " + + msg.getGroupId().hashCode() + ". " + + "Moving on to state " + nextState.name() + ); + } + + @Override + public StateUpdate<IS, BaseMessage> onMessageDelivered( + IS localState, BaseMessage delivered) { + try { + return noUpdate(localState, false); + } catch (FormatException e) { + if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + return null; + } + } + + private StateUpdate<IS, BaseMessage> abortSession( + InviteeSessionState.State currentState, IS localState) + throws FormatException { + + if (LOG.isLoggable(WARNING)) { + LOG.warning("Aborting protocol session " + + localState.getSessionId().hashCode() + + " in state " + currentState.name()); + } + localState.setState(InviteeSessionState.State.ERROR); + BaseMessage msg = + new SimpleMessage(SHARE_MSG_TYPE_ABORT, localState.getGroupId(), + localState.getSessionId()); + List<BaseMessage> messages = Collections.singletonList(msg); + + List<Event> events = Collections.emptyList(); + + return new StateUpdate<IS, BaseMessage>(false, false, + localState, messages, events); + } + + private StateUpdate<IS, BaseMessage> noUpdate( + IS localState, boolean delete) throws FormatException { + + return new StateUpdate<IS, BaseMessage>(delete, false, + localState, Collections.<BaseMessage>emptyList(), + Collections.<Event>emptyList()); + } +} diff --git a/briar-core/src/org/briarproject/forum/InviteeSessionState.java b/briar-core/src/org/briarproject/sharing/InviteeSessionState.java similarity index 66% rename from briar-core/src/org/briarproject/forum/InviteeSessionState.java rename to briar-core/src/org/briarproject/sharing/InviteeSessionState.java index 68b397bc726767ecc15b52f72526425470908725..6082c7ba8dfa3100ad56d539b419f14e853cb8e3 100644 --- a/briar-core/src/org/briarproject/forum/InviteeSessionState.java +++ b/briar-core/src/org/briarproject/sharing/InviteeSessionState.java @@ -1,4 +1,4 @@ -package org.briarproject.forum; +package org.briarproject.sharing; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.ContactId; @@ -6,28 +6,27 @@ import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; -import static org.briarproject.api.forum.ForumConstants.IS_SHARER; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_INVITATION; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.api.forum.ForumConstants.STATE; -import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_ACCEPT; -import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_DECLINE; -import static org.briarproject.forum.InviteeSessionState.Action.LOCAL_LEAVE; -import static org.briarproject.forum.InviteeSessionState.Action.REMOTE_INVITATION; -import static org.briarproject.forum.InviteeSessionState.Action.REMOTE_LEAVE; +import static org.briarproject.api.sharing.SharingConstants.IS_SHARER; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; +import static org.briarproject.api.sharing.SharingConstants.STATE; +import static org.briarproject.sharing.InviteeSessionState.Action.LOCAL_ACCEPT; +import static org.briarproject.sharing.InviteeSessionState.Action.LOCAL_DECLINE; +import static org.briarproject.sharing.InviteeSessionState.Action.LOCAL_LEAVE; +import static org.briarproject.sharing.InviteeSessionState.Action.REMOTE_INVITATION; +import static org.briarproject.sharing.InviteeSessionState.Action.REMOTE_LEAVE; // This class is not thread-safe -public class InviteeSessionState extends ForumSharingSessionState { +public abstract class InviteeSessionState extends SharingSessionState { private State state; public InviteeSessionState(SessionId sessionId, MessageId storageId, - GroupId groupId, State state, ContactId contactId, GroupId forumId, - String forumName, byte[] forumSalt) { + GroupId groupId, State state, ContactId contactId, + GroupId shareableId) { - super(sessionId, storageId, groupId, contactId, forumId, forumName, - forumSalt); + super(sessionId, storageId, groupId, contactId, shareableId); this.state = state; } diff --git a/briar-core/src/org/briarproject/sharing/InviteeSessionStateFactory.java b/briar-core/src/org/briarproject/sharing/InviteeSessionStateFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..57b8adcfaa4359a1e4dbdddf72c3841f467fa2e2 --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/InviteeSessionStateFactory.java @@ -0,0 +1,19 @@ +package org.briarproject.sharing; + +import org.briarproject.api.FormatException; +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.sharing.Shareable; +import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.MessageId; + +public interface InviteeSessionStateFactory<S extends Shareable, IS extends InviteeSessionState> { + + IS build(SessionId sessionId, MessageId storageId, GroupId groupId, + InviteeSessionState.State state, ContactId contactId, + GroupId shareableId, BdfDictionary d) throws FormatException; + + IS build(SessionId sessionId, MessageId storageId, GroupId groupId, + InviteeSessionState.State state, ContactId contactId, S shareable); +} diff --git a/briar-core/src/org/briarproject/sharing/ShareableFactory.java b/briar-core/src/org/briarproject/sharing/ShareableFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..6f961270da321073d3b9746b6ee217b7672aa4da --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/ShareableFactory.java @@ -0,0 +1,24 @@ +package org.briarproject.sharing; + +import org.briarproject.api.FormatException; +import org.briarproject.api.data.BdfList; +import org.briarproject.api.db.DbException; +import org.briarproject.api.db.Transaction; +import org.briarproject.api.sharing.Shareable; +import org.briarproject.api.sharing.SharingMessage; +import org.briarproject.api.sync.GroupId; + +interface ShareableFactory<S extends Shareable, I extends SharingMessage.Invitation, IS extends InviteeSessionState, SS extends SharerSessionState> { + + BdfList encode(S sh); + + S get(Transaction txn, GroupId groupId) throws DbException; + + S parse(BdfList shareable) throws FormatException; + + S parse(I msg); + + S parse(IS state); + + S parse(SS state); +} diff --git a/briar-core/src/org/briarproject/sharing/SharerEngine.java b/briar-core/src/org/briarproject/sharing/SharerEngine.java new file mode 100644 index 0000000000000000000000000000000000000000..7b09727c50a94bbd98a44d5bde199705c568d061 --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/SharerEngine.java @@ -0,0 +1,225 @@ +package org.briarproject.sharing; + +import org.briarproject.api.FormatException; +import org.briarproject.api.clients.ProtocolEngine; +import org.briarproject.api.event.Event; +import org.briarproject.api.event.InvitationResponseReceivedEvent; + +import java.util.Collections; +import java.util.List; +import java.util.logging.Logger; + +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; +import static org.briarproject.api.sharing.SharingConstants.TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US; +import static org.briarproject.api.sharing.SharingConstants.TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US; +import static org.briarproject.api.sharing.SharingConstants.TASK_SHARE_SHAREABLE; +import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_BY_US; +import static org.briarproject.api.sharing.SharingMessage.BaseMessage; +import static org.briarproject.api.sharing.SharingMessage.Invitation; +import static org.briarproject.api.sharing.SharingMessage.SimpleMessage; + +public class SharerEngine<I extends Invitation, SS extends SharerSessionState, IRR extends InvitationResponseReceivedEvent> + implements ProtocolEngine<SharerSessionState.Action, SS, BaseMessage> { + + private static final Logger LOG = + Logger.getLogger(SharerEngine.class.getName()); + + private final InvitationFactory<I, SS> invitationFactory; + private final InvitationResponseReceivedEventFactory<SS, IRR> + invitationResponseReceivedEventFactory; + + SharerEngine(InvitationFactory<I, SS> invitationFactory, + InvitationResponseReceivedEventFactory<SS, IRR> invitationResponseReceivedEventFactory) { + this.invitationFactory = invitationFactory; + this.invitationResponseReceivedEventFactory = + invitationResponseReceivedEventFactory; + } + + @Override + public StateUpdate<SS, BaseMessage> onLocalAction( + SS localState, SharerSessionState.Action action) { + + try { + SharerSessionState.State currentState = localState.getState(); + SharerSessionState.State nextState = currentState.next(action); + localState.setState(nextState); + + if (action == SharerSessionState.Action.LOCAL_ABORT && + currentState != SharerSessionState.State.ERROR) { + return abortSession(currentState, localState); + } + + if (nextState == SharerSessionState.State.ERROR) { + if (LOG.isLoggable(WARNING)) { + LOG.warning("Error: Invalid action in state " + + currentState.name()); + } + return noUpdate(localState, true); + } + List<BaseMessage> messages; + List<Event> events = Collections.emptyList(); + + if (action == SharerSessionState.Action.LOCAL_INVITATION) { + BaseMessage msg = invitationFactory.build(localState); + messages = Collections.singletonList(msg); + logLocalAction(currentState, nextState, msg); + + // remember that we offered to share this forum + localState + .setTask(TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US); + } else if (action == SharerSessionState.Action.LOCAL_LEAVE) { + BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE, + localState.getGroupId(), localState.getSessionId()); + messages = Collections.singletonList(msg); + logLocalAction(currentState, nextState, msg); + } else { + throw new IllegalArgumentException("Unknown Local Action"); + } + return new StateUpdate<SS, BaseMessage>(false, + false, localState, messages, events); + } catch (FormatException e) { + throw new IllegalArgumentException(e); + } + } + + @Override + public StateUpdate<SS, BaseMessage> onMessageReceived( + SS localState, BaseMessage msg) { + + try { + SharerSessionState.State currentState = localState.getState(); + SharerSessionState.Action action = + SharerSessionState.Action.getRemote(msg.getType()); + SharerSessionState.State nextState = currentState.next(action); + localState.setState(nextState); + + logMessageReceived(currentState, nextState, msg.getType(), msg); + + if (nextState == SharerSessionState.State.ERROR) { + if (currentState != SharerSessionState.State.ERROR) { + return abortSession(currentState, localState); + } else { + return noUpdate(localState, true); + } + } + List<BaseMessage> messages = Collections.emptyList(); + List<Event> events = Collections.emptyList(); + boolean deleteMsg = false; + + if (currentState == SharerSessionState.State.LEFT) { + // ignore and delete messages coming in while in that state + deleteMsg = true; + } else if (action == SharerSessionState.Action.REMOTE_LEAVE) { + localState.setTask(TASK_UNSHARE_SHAREABLE_SHARED_BY_US); + } else if (currentState == SharerSessionState.State.FINISHED) { + // ignore and delete messages coming in while in that state + // note that LEAVE is possible, but was handled above + deleteMsg = true; + } + // we have sent our invitation and just got a response + else if (action == SharerSessionState.Action.REMOTE_ACCEPT || + action == SharerSessionState.Action.REMOTE_DECLINE) { + if (action == SharerSessionState.Action.REMOTE_ACCEPT) { + localState.setTask(TASK_SHARE_SHAREABLE); + } else { + // this ensures that the forum can be shared again + localState.setTask( + TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US); + } + Event event = invitationResponseReceivedEventFactory + .build(localState); + events = Collections.singletonList(event); + } else { + throw new IllegalArgumentException("Bad state"); + } + return new StateUpdate<SS, BaseMessage>(deleteMsg, + false, localState, messages, events); + } catch (FormatException e) { + throw new IllegalArgumentException(e); + } + } + + private void logLocalAction(SharerSessionState.State currentState, + SharerSessionState.State nextState, + BaseMessage msg) { + + if (!LOG.isLoggable(INFO)) return; + + String a = "invitation"; + if (msg.getType() == SHARE_MSG_TYPE_LEAVE) a = "leave"; + + LOG.info("Sending " + a + " in state " + currentState.name() + + " with session ID " + + msg.getSessionId().hashCode() + " in group " + + msg.getGroupId().hashCode() + ". " + + "Moving on to state " + nextState.name() + ); + } + + private void logMessageReceived(SharerSessionState.State currentState, + SharerSessionState.State nextState, + long type, BaseMessage msg) { + + if (!LOG.isLoggable(INFO)) return; + + String t = "unknown"; + if (type == SHARE_MSG_TYPE_ACCEPT) t = "ACCEPT"; + else if (type == SHARE_MSG_TYPE_DECLINE) t = "DECLINE"; + else if (type == SHARE_MSG_TYPE_LEAVE) t = "LEAVE"; + else if (type == SHARE_MSG_TYPE_ABORT) t = "ABORT"; + + LOG.info("Received " + t + " in state " + currentState.name() + + " with session ID " + + msg.getSessionId().hashCode() + " in group " + + msg.getGroupId().hashCode() + ". " + + "Moving on to state " + nextState.name() + ); + } + + @Override + public StateUpdate<SS, BaseMessage> onMessageDelivered( + SS localState, BaseMessage delivered) { + try { + return noUpdate(localState, false); + } catch (FormatException e) { + if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + return null; + } + } + + private StateUpdate<SS, BaseMessage> abortSession( + SharerSessionState.State currentState, SS localState) + throws FormatException { + + if (LOG.isLoggable(WARNING)) { + LOG.warning("Aborting protocol session " + + localState.getSessionId().hashCode() + + " in state " + currentState.name()); + } + + localState.setState(SharerSessionState.State.ERROR); + BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_ABORT, + localState.getGroupId(), localState.getSessionId()); + List<BaseMessage> messages = Collections.singletonList(msg); + + List<Event> events = Collections.emptyList(); + + return new StateUpdate<SS, BaseMessage>(false, false, + localState, messages, events); + } + + private StateUpdate<SS, BaseMessage> noUpdate( + SS localState, boolean delete) + throws FormatException { + + return new StateUpdate<SS, BaseMessage>(delete, false, + localState, Collections.<BaseMessage>emptyList(), + Collections.<Event>emptyList()); + } + +} diff --git a/briar-core/src/org/briarproject/forum/SharerSessionState.java b/briar-core/src/org/briarproject/sharing/SharerSessionState.java similarity index 66% rename from briar-core/src/org/briarproject/forum/SharerSessionState.java rename to briar-core/src/org/briarproject/sharing/SharerSessionState.java index 6653648530e7e07a830ec50e5381f75e5a9c6e84..6cbb271561aea089a18e2e58357d4dabc7d88472 100644 --- a/briar-core/src/org/briarproject/forum/SharerSessionState.java +++ b/briar-core/src/org/briarproject/sharing/SharerSessionState.java @@ -1,4 +1,4 @@ -package org.briarproject.forum; +package org.briarproject.sharing; import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.ContactId; @@ -6,30 +6,29 @@ import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; -import static org.briarproject.api.forum.ForumConstants.IS_SHARER; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ACCEPT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_DECLINE; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.api.forum.ForumConstants.STATE; -import static org.briarproject.forum.SharerSessionState.Action.LOCAL_INVITATION; -import static org.briarproject.forum.SharerSessionState.Action.LOCAL_LEAVE; -import static org.briarproject.forum.SharerSessionState.Action.REMOTE_ACCEPT; -import static org.briarproject.forum.SharerSessionState.Action.REMOTE_DECLINE; -import static org.briarproject.forum.SharerSessionState.Action.REMOTE_LEAVE; +import static org.briarproject.api.sharing.SharingConstants.IS_SHARER; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; +import static org.briarproject.api.sharing.SharingConstants.STATE; +import static org.briarproject.sharing.SharerSessionState.Action.LOCAL_INVITATION; +import static org.briarproject.sharing.SharerSessionState.Action.LOCAL_LEAVE; +import static org.briarproject.sharing.SharerSessionState.Action.REMOTE_ACCEPT; +import static org.briarproject.sharing.SharerSessionState.Action.REMOTE_DECLINE; +import static org.briarproject.sharing.SharerSessionState.Action.REMOTE_LEAVE; // This class is not thread-safe -public class SharerSessionState extends ForumSharingSessionState { +public abstract class SharerSessionState extends SharingSessionState { private State state; private String msg = null; public SharerSessionState(SessionId sessionId, MessageId storageId, - GroupId groupId, State state, ContactId contactId, GroupId forumId, - String forumName, byte[] forumSalt) { + GroupId groupId, State state, ContactId contactId, + GroupId shareableId) { - super(sessionId, storageId, groupId, contactId, forumId, forumName, - forumSalt); + super(sessionId, storageId, groupId, contactId, shareableId); this.state = state; } diff --git a/briar-core/src/org/briarproject/sharing/SharerSessionStateFactory.java b/briar-core/src/org/briarproject/sharing/SharerSessionStateFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..d045114fc4710062ee142f660efbb4f86d07e8da --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/SharerSessionStateFactory.java @@ -0,0 +1,19 @@ +package org.briarproject.sharing; + +import org.briarproject.api.FormatException; +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.sharing.Shareable; +import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.MessageId; + +public interface SharerSessionStateFactory<S extends Shareable, SS extends SharerSessionState> { + + SS build(SessionId sessionId, MessageId storageId, GroupId groupId, + SharerSessionState.State state, ContactId contactId, + GroupId shareableId, BdfDictionary d) throws FormatException; + + SS build(SessionId sessionId, MessageId storageId, GroupId groupId, + SharerSessionState.State state, ContactId contactId, S shareable); +} diff --git a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java similarity index 65% rename from briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java rename to briar-core/src/org/briarproject/sharing/SharingManagerImpl.java index c03d781da293085113a06620c3385a1ba640fd0c..0d55b4a3cef39ef2fdb61609485968f343975c03 100644 --- a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java +++ b/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java @@ -1,4 +1,4 @@ -package org.briarproject.forum; +package org.briarproject.sharing; import org.briarproject.api.Bytes; import org.briarproject.api.FormatException; @@ -22,12 +22,12 @@ import org.briarproject.api.db.Metadata; import org.briarproject.api.db.NoSuchMessageException; import org.briarproject.api.db.Transaction; import org.briarproject.api.event.Event; -import org.briarproject.api.forum.Forum; -import org.briarproject.api.forum.ForumFactory; -import org.briarproject.api.forum.ForumInvitationMessage; -import org.briarproject.api.forum.ForumManager; -import org.briarproject.api.forum.ForumSharingManager; +import org.briarproject.api.event.InvitationReceivedEvent; +import org.briarproject.api.event.InvitationResponseReceivedEvent; import org.briarproject.api.identity.LocalAuthor; +import org.briarproject.api.sharing.InvitationMessage; +import org.briarproject.api.sharing.Shareable; +import org.briarproject.api.sharing.SharingManager; import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.Group; import org.briarproject.api.sync.GroupId; @@ -50,83 +50,90 @@ import java.util.Map; import java.util.Set; import java.util.logging.Logger; -import javax.inject.Inject; - import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static org.briarproject.api.clients.ProtocolEngine.StateUpdate; -import static org.briarproject.api.forum.ForumConstants.CONTACT_ID; -import static org.briarproject.api.forum.ForumConstants.FORUM_ID; -import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH; -import static org.briarproject.api.forum.ForumConstants.IS_SHARER; -import static org.briarproject.api.forum.ForumConstants.LOCAL; -import static org.briarproject.api.forum.ForumConstants.READ; -import static org.briarproject.api.forum.ForumConstants.SESSION_ID; -import static org.briarproject.api.forum.ForumConstants.SHARED_BY_US; -import static org.briarproject.api.forum.ForumConstants.SHARED_WITH_US; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_ACCEPT; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_DECLINE; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_INVITATION; -import static org.briarproject.api.forum.ForumConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.api.forum.ForumConstants.STATE; -import static org.briarproject.api.forum.ForumConstants.TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US; -import static org.briarproject.api.forum.ForumConstants.TASK_ADD_FORUM_TO_LIST_TO_BE_SHARED_BY_US; -import static org.briarproject.api.forum.ForumConstants.TASK_ADD_SHARED_FORUM; -import static org.briarproject.api.forum.ForumConstants.TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US; -import static org.briarproject.api.forum.ForumConstants.TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US; -import static org.briarproject.api.forum.ForumConstants.TASK_SHARE_FORUM; -import static org.briarproject.api.forum.ForumConstants.TASK_UNSHARE_FORUM_SHARED_BY_US; -import static org.briarproject.api.forum.ForumConstants.TASK_UNSHARE_FORUM_SHARED_WITH_US; -import static org.briarproject.api.forum.ForumConstants.TIME; -import static org.briarproject.api.forum.ForumConstants.TO_BE_SHARED_BY_US; -import static org.briarproject.api.forum.ForumConstants.TYPE; -import static org.briarproject.api.forum.ForumManager.RemoveForumHook; -import static org.briarproject.api.forum.ForumSharingMessage.BaseMessage; -import static org.briarproject.api.forum.ForumSharingMessage.Invitation; -import static org.briarproject.forum.ForumSharingSessionState.fromBdfDictionary; -import static org.briarproject.forum.SharerSessionState.Action; - -class ForumSharingManagerImpl extends BdfIncomingMessageHook - implements ForumSharingManager, Client, RemoveForumHook, - AddContactHook, RemoveContactHook { - - static final ClientId CLIENT_ID = new ClientId(StringUtils.fromHexString( - "cd11a5d04dccd9e2931d6fc3df456313" - + "63bb3e9d9d0e9405fccdb051f41f5449")); +import static org.briarproject.api.sharing.SharingConstants.CONTACT_ID; +import static org.briarproject.api.sharing.SharingConstants.IS_SHARER; +import static org.briarproject.api.sharing.SharingConstants.LOCAL; +import static org.briarproject.api.sharing.SharingConstants.READ; +import static org.briarproject.api.sharing.SharingConstants.SESSION_ID; +import static org.briarproject.api.sharing.SharingConstants.SHAREABLE_ID; +import static org.briarproject.api.sharing.SharingConstants.SHARED_BY_US; +import static org.briarproject.api.sharing.SharingConstants.SHARED_WITH_US; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; +import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; +import static org.briarproject.api.sharing.SharingConstants.SHARING_SALT_LENGTH; +import static org.briarproject.api.sharing.SharingConstants.STATE; +import static org.briarproject.api.sharing.SharingConstants.TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US; +import static org.briarproject.api.sharing.SharingConstants.TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US; +import static org.briarproject.api.sharing.SharingConstants.TASK_ADD_SHARED_SHAREABLE; +import static org.briarproject.api.sharing.SharingConstants.TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US; +import static org.briarproject.api.sharing.SharingConstants.TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US; +import static org.briarproject.api.sharing.SharingConstants.TASK_SHARE_SHAREABLE; +import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_BY_US; +import static org.briarproject.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_WITH_US; +import static org.briarproject.api.sharing.SharingConstants.TIME; +import static org.briarproject.api.sharing.SharingConstants.TO_BE_SHARED_BY_US; +import static org.briarproject.api.sharing.SharingConstants.TYPE; +import static org.briarproject.api.sharing.SharingMessage.BaseMessage; +import static org.briarproject.api.sharing.SharingMessage.Invitation; + +abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IM extends InvitationMessage, IS extends InviteeSessionState, SS extends SharerSessionState, IR extends InvitationReceivedEvent, IRR extends InvitationResponseReceivedEvent> + extends BdfIncomingMessageHook + implements SharingManager<S, IM>, Client, AddContactHook, + RemoveContactHook { private static final Logger LOG = - Logger.getLogger(ForumSharingManagerImpl.class.getName()); + Logger.getLogger(SharingManagerImpl.class.getName()); private final DatabaseComponent db; - private final ForumManager forumManager; private final MessageQueueManager messageQueueManager; private final MetadataEncoder metadataEncoder; private final SecureRandom random; private final PrivateGroupFactory privateGroupFactory; - private final ForumFactory forumFactory; private final Clock clock; private final Group localGroup; - @Inject - ForumSharingManagerImpl(DatabaseComponent db, ForumManager forumManager, + SharingManagerImpl(DatabaseComponent db, MessageQueueManager messageQueueManager, ClientHelper clientHelper, MetadataParser metadataParser, MetadataEncoder metadataEncoder, SecureRandom random, PrivateGroupFactory privateGroupFactory, - ForumFactory forumFactory, Clock clock) { + Clock clock) { super(clientHelper, metadataParser); this.db = db; - this.forumManager = forumManager; this.messageQueueManager = messageQueueManager; this.metadataEncoder = metadataEncoder; this.random = random; this.privateGroupFactory = privateGroupFactory; - this.forumFactory = forumFactory; this.clock = clock; localGroup = privateGroupFactory.createLocalGroup(getClientId()); } + public abstract ClientId getClientId(); + + protected abstract ClientId getShareableClientId(); + + protected abstract IM createInvitationMessage(MessageId id, I msg, + ContactId contactId, boolean available, long time, boolean local, + boolean sent, boolean seen, boolean read); + + protected abstract ShareableFactory<S, I, IS, SS> getSFactory(); + + protected abstract InvitationFactory<I, SS> getIFactory(); + + protected abstract InviteeSessionStateFactory<S, IS> getISFactory(); + + protected abstract SharerSessionStateFactory<S, SS> getSSFactory(); + + protected abstract InvitationReceivedEventFactory<IS, IR> getIRFactory(); + + protected abstract InvitationResponseReceivedEventFactory<SS, IRR> getIRRFactory(); + @Override public void createLocalState(Transaction txn) throws DbException { db.addGroup(txn, localGroup); @@ -183,7 +190,7 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook protected void incomingMessage(Transaction txn, Message m, BdfList body, BdfDictionary d) throws DbException, FormatException { - BaseMessage msg = BaseMessage.from(m.getGroupId(), d); + BaseMessage msg = BaseMessage.from(getIFactory(), m.getGroupId(), d); SessionId sessionId = msg.getSessionId(); if (msg.getType() == SHARE_MSG_TYPE_INVITATION) { @@ -200,19 +207,18 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook // check if we already have a state with that sessionId if (stateExists) throw new FormatException(); - // check if forum can be shared - Invitation invitation = (Invitation) msg; - Forum f = forumFactory.createForum(invitation.getForumName(), - invitation.getForumSalt()); + // check if shareable can be shared + I invitation = (I) msg; + S f = getSFactory().parse(invitation); ContactId contactId = getContactId(txn, m.getGroupId()); Contact contact = db.getContact(txn, contactId); if (!canBeShared(txn, f.getId(), contact)) checkForRaceCondition(txn, f, contact); // initialize state and process invitation - InviteeSessionState state = - initializeInviteeState(txn, contactId, invitation); - InviteeEngine engine = new InviteeEngine(forumFactory); + IS state = initializeInviteeState(txn, contactId, invitation); + InviteeEngine<IS, IR> engine = + new InviteeEngine<IS, IR>(getIRFactory()); processInviteeStateUpdate(txn, m.getId(), engine.onMessageReceived(state, msg)); } catch (FormatException e) { @@ -222,48 +228,47 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } else if (msg.getType() == SHARE_MSG_TYPE_ACCEPT || msg.getType() == SHARE_MSG_TYPE_DECLINE) { // we are a sharer who just received a response - SharerSessionState state = getSessionStateForSharer(txn, sessionId); - SharerEngine engine = new SharerEngine(); + SS state = getSessionStateForSharer(txn, sessionId); + SharerEngine<I, SS, IRR> engine = + new SharerEngine<I, SS, IRR>(getIFactory(), + getIRRFactory()); processSharerStateUpdate(txn, m.getId(), engine.onMessageReceived(state, msg)); } else if (msg.getType() == SHARE_MSG_TYPE_LEAVE || msg.getType() == SHARE_MSG_TYPE_ABORT) { // we don't know who we are, so figure it out - ForumSharingSessionState s = getSessionState(txn, sessionId, true); + SharingSessionState s = getSessionState(txn, sessionId, true); if (s instanceof SharerSessionState) { // we are a sharer and the invitee wants to leave or abort - SharerSessionState state = (SharerSessionState) s; - SharerEngine engine = new SharerEngine(); + SS state = (SS) s; + SharerEngine<I, SS, IRR> engine = + new SharerEngine<I, SS, IRR>(getIFactory(), + getIRRFactory()); processSharerStateUpdate(txn, m.getId(), engine.onMessageReceived(state, msg)); } else { // we are an invitee and the sharer wants to leave or abort - InviteeSessionState state = (InviteeSessionState) s; - InviteeEngine engine = new InviteeEngine(forumFactory); + IS state = (IS) s; + InviteeEngine<IS, IR> engine = + new InviteeEngine<IS, IR>(getIRFactory()); processInviteeStateUpdate(txn, m.getId(), engine.onMessageReceived(state, msg)); } } else { // message has passed validator, so that should never happen - throw new RuntimeException("Illegal Forum Sharing Message"); + throw new RuntimeException("Illegal Sharing Message"); } } @Override - public ClientId getClientId() { - return CLIENT_ID; - } - - @Override - public void sendForumInvitation(GroupId groupId, ContactId contactId, + public void sendInvitation(GroupId groupId, ContactId contactId, String msg) throws DbException { Transaction txn = db.startTransaction(false); try { // initialize local state for sharer - Forum f = forumManager.getForum(txn, groupId); - SharerSessionState localState = - initializeSharerState(txn, f, contactId); + S f = getSFactory().get(txn, groupId); + SS localState = initializeSharerState(txn, f, contactId); // add invitation message to local state to be available for engine if (!StringUtils.isNullOrEmpty(msg)) { @@ -271,9 +276,12 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } // start engine and process its state update - SharerEngine engine = new SharerEngine(); + SharerEngine<I, SS, IRR> engine = + new SharerEngine<I, SS, IRR>(getIFactory(), + getIRRFactory()); processSharerStateUpdate(txn, null, - engine.onLocalAction(localState, Action.LOCAL_INVITATION)); + engine.onLocalAction(localState, + SharerSessionState.Action.LOCAL_INVITATION)); txn.setComplete(); } catch (FormatException e) { @@ -284,14 +292,13 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } @Override - public void respondToInvitation(Forum f, Contact c, boolean accept) + public void respondToInvitation(S f, Contact c, boolean accept) throws DbException { Transaction txn = db.startTransaction(false); try { - // find session state based on forum - InviteeSessionState localState = - getSessionStateForResponse(txn, f, c); + // find session state based on shareable + IS localState = getSessionStateForResponse(txn, f, c); // define action InviteeSessionState.Action localAction; @@ -302,7 +309,8 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } // start engine and process its state update - InviteeEngine engine = new InviteeEngine(forumFactory); + InviteeEngine<IS, IR> engine = + new InviteeEngine<IS, IR>(getIRFactory()); processInviteeStateUpdate(txn, null, engine.onLocalAction(localState, localAction)); @@ -315,8 +323,8 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } @Override - public Collection<ForumInvitationMessage> getForumInvitationMessages( - ContactId contactId) throws DbException { + public Collection<IM> getInvitationMessages(ContactId contactId) + throws DbException { // query for all invitations BdfDictionary query = BdfDictionary.of( @@ -328,14 +336,13 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook Contact contact = db.getContact(txn, contactId); Group group = getContactGroup(contact); - Collection<ForumInvitationMessage> list = - new ArrayList<ForumInvitationMessage>(); + Collection<IM> list = new ArrayList<IM>(); Map<MessageId, BdfDictionary> map = clientHelper .getMessageMetadataAsDictionary(txn, group.getId(), query); for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) { BdfDictionary d = m.getValue(); try { - Invitation msg = Invitation.from(group.getId(), d); + I msg = getIFactory().build(group.getId(), d); MessageStatus status = db.getMessageStatus(txn, contactId, m.getKey()); long time = d.getLong(TIME); @@ -343,20 +350,17 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook boolean read = d.getBoolean(READ, false); boolean available = false; if (!local) { - // figure out whether the forum is still available - ForumSharingSessionState s = + // figure out whether the shareable is still available + SharingSessionState s = getSessionState(txn, msg.getSessionId(), true); if (!(s instanceof InviteeSessionState)) continue; available = ((InviteeSessionState) s).getState() == InviteeSessionState.State.AWAIT_LOCAL_RESPONSE; } - ForumInvitationMessage im = - new ForumInvitationMessage(m.getKey(), - msg.getSessionId(), contactId, - msg.getForumName(), msg.getMessage(), - available, time, local, status.isSent(), - status.isSeen(), read); + IM im = createInvitationMessage(m.getKey(), msg, contactId, + available, time, local, status.isSent(), + status.isSeen(), read); list.add(im); } catch (FormatException e) { if (LOG.isLoggable(WARNING)) @@ -373,40 +377,20 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } @Override - public void removingForum(Transaction txn, Forum f) throws DbException { + public Collection<S> getAvailable() throws DbException { try { - for (Contact c : db.getContacts(txn)) { - GroupId g = getContactGroup(c).getId(); - if (removeFromList(txn, g, TO_BE_SHARED_BY_US, f)) { - leaveForum(txn, c.getId(), f); - } - if (removeFromList(txn, g, SHARED_BY_US, f)) { - leaveForum(txn, c.getId(), f); - } - if (removeFromList(txn, g, SHARED_WITH_US, f)) { - leaveForum(txn, c.getId(), f); - } - } - } catch (IOException e) { - throw new DbException(e); - } - } - - @Override - public Collection<Forum> getAvailableForums() throws DbException { - try { - Set<Forum> available = new HashSet<Forum>(); + Set<S> available = new HashSet<S>(); Transaction txn = db.startTransaction(true); try { - // Get any forums we subscribe to + // Get any shareables we subscribe to Set<Group> subscribed = new HashSet<Group>(db.getGroups(txn, - forumManager.getClientId())); - // Get all forums shared by contacts + getShareableClientId())); + // Get all shareables shared by contacts for (Contact c : db.getContacts(txn)) { Group g = getContactGroup(c); - List<Forum> forums = - getForumList(txn, g.getId(), SHARED_WITH_US); - for (Forum f : forums) { + List<S> shareables = + getShareableList(txn, g.getId(), SHARED_WITH_US); + for (S f : shareables) { if (!subscribed.contains(f.getGroup())) available.add(f); } @@ -489,7 +473,26 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } } - private void checkForRaceCondition(Transaction txn, Forum f, Contact c) + protected void removingShareable(Transaction txn, S f) throws DbException { + try { + for (Contact c : db.getContacts(txn)) { + GroupId g = getContactGroup(c).getId(); + if (removeFromList(txn, g, TO_BE_SHARED_BY_US, f)) { + leaveShareable(txn, c.getId(), f); + } + if (removeFromList(txn, g, SHARED_BY_US, f)) { + leaveShareable(txn, c.getId(), f); + } + if (removeFromList(txn, g, SHARED_WITH_US, f)) { + leaveShareable(txn, c.getId(), f); + } + } + } catch (IOException e) { + throw new DbException(e); + } + } + + private void checkForRaceCondition(Transaction txn, S f, Contact c) throws FormatException, DbException { GroupId contactGroup = getContactGroup(c).getId(); @@ -507,12 +510,14 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook if (alice) { // our own invitation takes precedence, so just delete Bob's - LOG.info("Invitation race-condition: We are Alice deleting Bob's invitation."); + LOG.info( + "Invitation race-condition: We are Alice deleting Bob's invitation."); throw new FormatException(); } else { // we are Bob, so we need to "take back" our own invitation - LOG.info("Invitation race-condition: We are Bob taking back our invitation."); - ForumSharingSessionState state = + LOG.info( + "Invitation race-condition: We are Bob taking back our invitation."); + SharingSessionState state = getSessionStateForLeaving(txn, f, c.getId()); if (state instanceof SharerSessionState) { //SharerEngine engine = new SharerEngine(); @@ -529,7 +534,7 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } - private SharerSessionState initializeSharerState(Transaction txn, Forum f, + private SS initializeSharerState(Transaction txn, S f, ContactId contactId) throws FormatException, DbException { Contact c = db.getContact(txn, contactId); @@ -537,15 +542,15 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook // create local message to keep engine state long now = clock.currentTimeMillis(); - Bytes salt = new Bytes(new byte[FORUM_SALT_LENGTH]); + Bytes salt = new Bytes(new byte[SHARING_SALT_LENGTH]); random.nextBytes(salt.getBytes()); Message m = clientHelper.createMessage(localGroup.getId(), now, BdfList.of(salt)); SessionId sessionId = new SessionId(m.getId().getBytes()); - SharerSessionState s = new SharerSessionState(sessionId, sessionId, + SS s = getSSFactory().build(sessionId, sessionId, group.getId(), SharerSessionState.State.PREPARE_INVITATION, - contactId, f.getId(), f.getName(), f.getSalt()); + contactId, f); // save local state to database BdfDictionary d = s.toBdfDictionary(); @@ -554,27 +559,24 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook return s; } - private InviteeSessionState initializeInviteeState(Transaction txn, - ContactId contactId, Invitation msg) + private IS initializeInviteeState(Transaction txn, + ContactId contactId, I msg) throws FormatException, DbException { Contact c = db.getContact(txn, contactId); Group group = getContactGroup(c); - String name = msg.getForumName(); - byte[] salt = msg.getForumSalt(); - Forum f = forumFactory.createForum(name, salt); + S f = getSFactory().parse(msg); // create local message to keep engine state long now = clock.currentTimeMillis(); - Bytes mSalt = new Bytes(new byte[FORUM_SALT_LENGTH]); + Bytes mSalt = new Bytes(new byte[SHARING_SALT_LENGTH]); random.nextBytes(mSalt.getBytes()); Message m = clientHelper.createMessage(localGroup.getId(), now, BdfList.of(mSalt)); - InviteeSessionState s = new InviteeSessionState(msg.getSessionId(), + IS s = getISFactory().build(msg.getSessionId(), m.getId(), group.getId(), - InviteeSessionState.State.AWAIT_INVITATION, contactId, - f.getId(), f.getName(), f.getSalt()); + InviteeSessionState.State.AWAIT_INVITATION, contactId, f); // save local state to database BdfDictionary d = s.toBdfDictionary(); @@ -583,7 +585,7 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook return s; } - private ForumSharingSessionState getSessionState(Transaction txn, + private SharingSessionState getSessionState(Transaction txn, SessionId sessionId, boolean warn) throws DbException, FormatException { @@ -612,11 +614,13 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } throw new FormatException(); } - return fromBdfDictionary(map.values().iterator().next()); + return SharingSessionState + .fromBdfDictionary(getISFactory(), getSSFactory(), + map.values().iterator().next()); } } - private SharerSessionState getSessionStateForSharer(Transaction txn, + private SS getSessionStateForSharer(Transaction txn, SessionId sessionId) throws DbException, FormatException { @@ -626,17 +630,18 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook if (!d.getBoolean(IS_SHARER)) throw new FormatException(); - return (SharerSessionState) fromBdfDictionary(d); + return (SS) SharingSessionState + .fromBdfDictionary(getISFactory(), getSSFactory(), d); } - private InviteeSessionState getSessionStateForResponse(Transaction txn, - Forum f, Contact c) throws DbException, FormatException { + private IS getSessionStateForResponse(Transaction txn, + S f, Contact c) throws DbException, FormatException { - // query for invitee states for that forum in state await response + // query for invitee states for that shareable in state await response BdfDictionary query = BdfDictionary.of( new BdfEntry(IS_SHARER, false), new BdfEntry(CONTACT_ID, c.getId().getInt()), - new BdfEntry(FORUM_ID, f.getId()), + new BdfEntry(SHAREABLE_ID, f.getId()), new BdfEntry(STATE, InviteeSessionState.State.AWAIT_LOCAL_RESPONSE .getValue()) @@ -647,7 +652,7 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook if (map.size() > 1 && LOG.isLoggable(WARNING)) { LOG.warning( - "More than one session state found for forum with ID " + + "More than one session state found for shareable with ID " + Arrays.hashCode(f.getId().getBytes()) + " in state AWAIT_LOCAL_RESPONSE for contact " + c.getAuthor().getName()); @@ -655,35 +660,38 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook if (map.isEmpty()) { if (LOG.isLoggable(WARNING)) { LOG.warning( - "No session state found for forum with ID " + + "No session state found for shareable with ID " + Arrays.hashCode(f.getId().getBytes()) + " in state AWAIT_LOCAL_RESPONSE"); } throw new DbException(); } - return (InviteeSessionState) fromBdfDictionary( - map.values().iterator().next()); + return (IS) SharingSessionState + .fromBdfDictionary(getISFactory(), getSSFactory(), + map.values().iterator().next()); } - private ForumSharingSessionState getSessionStateForLeaving(Transaction txn, - Forum f, ContactId c) throws DbException, FormatException { + private SharingSessionState getSessionStateForLeaving(Transaction txn, + S f, ContactId c) throws DbException, FormatException { BdfDictionary query = BdfDictionary.of( new BdfEntry(CONTACT_ID, c.getInt()), - new BdfEntry(FORUM_ID, f.getId()) + new BdfEntry(SHAREABLE_ID, f.getId()) ); Map<MessageId, BdfDictionary> map = clientHelper .getMessageMetadataAsDictionary(txn, localGroup.getId(), query); for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) { BdfDictionary d = m.getValue(); try { - ForumSharingSessionState s = fromBdfDictionary(d); + SharingSessionState s = SharingSessionState + .fromBdfDictionary(getISFactory(), getSSFactory(), d); - // check that a forum get be left in current session + // check that a shareable get be left in current session if (s instanceof SharerSessionState) { SharerSessionState state = (SharerSessionState) s; SharerSessionState.State nextState = - state.getState().next(Action.LOCAL_LEAVE); + state.getState() + .next(SharerSessionState.Action.LOCAL_LEAVE); if (nextState != SharerSessionState.State.ERROR) { return state; } @@ -703,11 +711,11 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } private void processStateUpdate(Transaction txn, MessageId messageId, - StateUpdate<ForumSharingSessionState, BaseMessage> result) + StateUpdate<SharingSessionState, BaseMessage> result, S f) throws DbException, FormatException { // perform actions based on new local state - performTasks(txn, result.localState); + performTasks(txn, result.localState, f); // save new local state MessageId storageId = result.localState.getStorageId(); @@ -735,31 +743,37 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } private void processSharerStateUpdate(Transaction txn, MessageId messageId, - StateUpdate<SharerSessionState, BaseMessage> result) + StateUpdate<SS, BaseMessage> result) throws DbException, FormatException { - StateUpdate<ForumSharingSessionState, BaseMessage> r = - new StateUpdate<ForumSharingSessionState, BaseMessage>( + StateUpdate<SharingSessionState, BaseMessage> r = + new StateUpdate<SharingSessionState, BaseMessage>( result.deleteMessage, result.deleteState, result.localState, result.toSend, result.toBroadcast); - processStateUpdate(txn, messageId, r); + // get shareable for later + S f = getSFactory().parse(result.localState); + + processStateUpdate(txn, messageId, r, f); } private void processInviteeStateUpdate(Transaction txn, MessageId messageId, - StateUpdate<InviteeSessionState, BaseMessage> result) + StateUpdate<IS, BaseMessage> result) throws DbException, FormatException { - StateUpdate<ForumSharingSessionState, BaseMessage> r = - new StateUpdate<ForumSharingSessionState, BaseMessage>( + StateUpdate<SharingSessionState, BaseMessage> r = + new StateUpdate<SharingSessionState, BaseMessage>( result.deleteMessage, result.deleteState, result.localState, result.toSend, result.toBroadcast); - processStateUpdate(txn, messageId, r); + // get shareable for later + S f = getSFactory().parse(result.localState); + + processStateUpdate(txn, messageId, r, f); } - private void performTasks(Transaction txn, ForumSharingSessionState localState) - throws FormatException, DbException { + private void performTasks(Transaction txn, SharingSessionState localState, + S f) throws FormatException, DbException { if (localState.getTask() == -1) return; @@ -772,37 +786,26 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook // get contact ID for later ContactId contactId = localState.getContactId(); - // get forum for later - String name = localState.getForumName(); - byte[] salt = localState.getForumSalt(); - Forum f = forumFactory.createForum(name, salt); - // perform tasks - if (task == TASK_ADD_FORUM_TO_LIST_SHARED_WITH_US) { + if (task == TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US) { addToList(txn, groupId, SHARED_WITH_US, f); - } - else if (task == TASK_REMOVE_FORUM_FROM_LIST_SHARED_WITH_US) { + } else if (task == TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US) { removeFromList(txn, groupId, SHARED_WITH_US, f); - } - else if (task == TASK_ADD_SHARED_FORUM) { + } else if (task == TASK_ADD_SHARED_SHAREABLE) { db.addGroup(txn, f.getGroup()); db.setVisibleToContact(txn, contactId, f.getId(), true); - } - else if (task == TASK_ADD_FORUM_TO_LIST_TO_BE_SHARED_BY_US) { + } else if (task == TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US) { addToList(txn, groupId, TO_BE_SHARED_BY_US, f); - } - else if (task == TASK_REMOVE_FORUM_FROM_LIST_TO_BE_SHARED_BY_US) { + } else if (task == TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US) { removeFromList(txn, groupId, TO_BE_SHARED_BY_US, f); - } - else if (task == TASK_SHARE_FORUM) { + } else if (task == TASK_SHARE_SHAREABLE) { db.setVisibleToContact(txn, contactId, f.getId(), true); removeFromList(txn, groupId, TO_BE_SHARED_BY_US, f); addToList(txn, groupId, SHARED_BY_US, f); - } - else if (task == TASK_UNSHARE_FORUM_SHARED_BY_US) { + } else if (task == TASK_UNSHARE_SHAREABLE_SHARED_BY_US) { db.setVisibleToContact(txn, contactId, f.getId(), false); removeFromList(txn, groupId, SHARED_BY_US, f); - } else if (task == TASK_UNSHARE_FORUM_SHARED_WITH_US) { + } else if (task == TASK_UNSHARE_SHAREABLE_SHARED_WITH_US) { db.setVisibleToContact(txn, contactId, f.getId(), false); removeFromList(txn, groupId, SHARED_WITH_US, f); } @@ -826,7 +829,7 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook } private Group getContactGroup(Contact c) { - return privateGroupFactory.createPrivateGroup(CLIENT_ID, c); + return privateGroupFactory.createPrivateGroup(getClientId(), c); } private ContactId getContactId(Transaction txn, GroupId contactGroupId) @@ -836,90 +839,94 @@ class ForumSharingManagerImpl extends BdfIncomingMessageHook return new ContactId(meta.getLong(CONTACT_ID).intValue()); } - private void leaveForum(Transaction txn, ContactId c, Forum f) + private void leaveShareable(Transaction txn, ContactId c, S f) throws DbException, FormatException { - ForumSharingSessionState state = getSessionStateForLeaving(txn, f, c); + SharingSessionState state = getSessionStateForLeaving(txn, f, c); if (state instanceof SharerSessionState) { - Action action = Action.LOCAL_LEAVE; - SharerEngine engine = new SharerEngine(); + SharerSessionState.Action action = + SharerSessionState.Action.LOCAL_LEAVE; + SharerEngine<I, SS, IRR> engine = + new SharerEngine<I, SS, IRR>(getIFactory(), + getIRRFactory()); processSharerStateUpdate(txn, null, - engine.onLocalAction((SharerSessionState) state, action)); + engine.onLocalAction((SS) state, action)); } else { InviteeSessionState.Action action = InviteeSessionState.Action.LOCAL_LEAVE; - InviteeEngine engine = new InviteeEngine(forumFactory); + InviteeEngine<IS, IR> engine = + new InviteeEngine<IS, IR>(getIRFactory()); processInviteeStateUpdate(txn, null, - engine.onLocalAction((InviteeSessionState) state, action)); + engine.onLocalAction((IS) state, action)); } } private boolean listContains(Transaction txn, GroupId contactGroup, - GroupId forum, String key) throws DbException, FormatException { + GroupId shareable, String key) throws DbException, FormatException { - List<Forum> list = getForumList(txn, contactGroup, key); - for (Forum f : list) { - if (f.getId().equals(forum)) return true; + List<S> list = getShareableList(txn, contactGroup, key); + for (S f : list) { + if (f.getId().equals(shareable)) return true; } return false; } private boolean addToList(Transaction txn, GroupId groupId, String key, - Forum f) throws DbException, FormatException { + S f) throws DbException, FormatException { - List<Forum> forums = getForumList(txn, groupId, key); - if (forums.contains(f)) return false; - forums.add(f); - storeForumList(txn, groupId, key, forums); + List<S> shareables = getShareableList(txn, groupId, key); + if (shareables.contains(f)) return false; + shareables.add(f); + storeShareableList(txn, groupId, key, shareables); return true; } private boolean removeFromList(Transaction txn, GroupId groupId, String key, - Forum f) throws DbException, FormatException { + S f) throws DbException, FormatException { - List<Forum> forums = getForumList(txn, groupId, key); - if (forums.remove(f)) { - storeForumList(txn, groupId, key, forums); + List<S> shareables = getShareableList(txn, groupId, key); + if (shareables.remove(f)) { + storeShareableList(txn, groupId, key, shareables); return true; } return false; } - private List<Forum> getForumList(Transaction txn, GroupId groupId, + private List<S> getShareableList(Transaction txn, GroupId groupId, String key) throws DbException, FormatException { BdfDictionary metadata = clientHelper.getGroupMetadataAsDictionary(txn, groupId); BdfList list = metadata.getList(key); - return parseForumList(list); + return parseShareableList(list); } - private void storeForumList(Transaction txn, GroupId groupId, String key, - List<Forum> forums) throws DbException, FormatException { + private void storeShareableList(Transaction txn, GroupId groupId, + String key, + List<S> shareables) throws DbException, FormatException { - BdfList list = encodeForumList(forums); + BdfList list = encodeShareableList(shareables); BdfDictionary metadata = BdfDictionary.of( new BdfEntry(key, list) ); clientHelper.mergeGroupMetadata(txn, groupId, metadata); } - private BdfList encodeForumList(List<Forum> forums) { - BdfList forumList = new BdfList(); - for (Forum f : forums) - forumList.add(BdfList.of(f.getName(), f.getSalt())); - return forumList; + private BdfList encodeShareableList(List<S> shareables) { + BdfList shareableList = new BdfList(); + for (S f : shareables) + shareableList.add(getSFactory().encode(f)); + return shareableList; } - private List<Forum> parseForumList(BdfList list) throws FormatException { - List<Forum> forums = new ArrayList<Forum>(list.size()); + private List<S> parseShareableList(BdfList list) throws FormatException { + List<S> shareables = new ArrayList<S>(list.size()); for (int i = 0; i < list.size(); i++) { - BdfList forum = list.getList(i); - forums.add(forumFactory - .createForum(forum.getString(0), forum.getRaw(1))); + BdfList shareable = list.getList(i); + shareables.add(getSFactory().parse(shareable)); } - return forums; + return shareables; } private void deleteMessage(Transaction txn, MessageId messageId) diff --git a/briar-core/src/org/briarproject/sharing/SharingModule.java b/briar-core/src/org/briarproject/sharing/SharingModule.java new file mode 100644 index 0000000000000000000000000000000000000000..d62c7dccf7945810b7d271e85c4ac43e78131268 --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/SharingModule.java @@ -0,0 +1,97 @@ +package org.briarproject.sharing; + +import org.briarproject.api.blogs.BlogSharingManager; +import org.briarproject.api.clients.ClientHelper; +import org.briarproject.api.clients.MessageQueueManager; +import org.briarproject.api.contact.ContactManager; +import org.briarproject.api.data.MetadataEncoder; +import org.briarproject.api.forum.ForumManager; +import org.briarproject.api.forum.ForumSharingManager; +import org.briarproject.api.lifecycle.LifecycleManager; +import org.briarproject.api.system.Clock; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class SharingModule { + + public static class EagerSingletons { + @Inject + BlogSharingValidator blogSharingValidator; + @Inject + ForumSharingValidator forumSharingValidator; + @Inject + ForumSharingManager forumSharingManager; + } + + @Provides + @Singleton + BlogSharingValidator provideBlogSharingValidator( + MessageQueueManager messageQueueManager, ClientHelper clientHelper, + MetadataEncoder metadataEncoder, Clock clock) { + + BlogSharingValidator + validator = new BlogSharingValidator(clientHelper, + metadataEncoder, clock); + messageQueueManager.registerMessageValidator( + BlogSharingManagerImpl.CLIENT_ID, validator); + + return validator; + } + + @Provides + @Singleton + BlogSharingManager provideBlogSharingManager( + LifecycleManager lifecycleManager, + ContactManager contactManager, + MessageQueueManager messageQueueManager, + BlogSharingManagerImpl blogSharingManager) { + + lifecycleManager.registerClient(blogSharingManager); + contactManager.registerAddContactHook(blogSharingManager); + contactManager.registerRemoveContactHook(blogSharingManager); + messageQueueManager.registerIncomingMessageHook( + BlogSharingManagerImpl.CLIENT_ID, blogSharingManager); + + return blogSharingManager; + } + + @Provides + @Singleton + ForumSharingValidator provideForumSharingValidator( + MessageQueueManager messageQueueManager, ClientHelper clientHelper, + MetadataEncoder metadataEncoder, Clock clock) { + + ForumSharingValidator + validator = new ForumSharingValidator(clientHelper, + metadataEncoder, clock); + messageQueueManager.registerMessageValidator( + ForumSharingManagerImpl.CLIENT_ID, validator); + + return validator; + } + + @Provides + @Singleton + ForumSharingManager provideForumSharingManager( + LifecycleManager lifecycleManager, + ContactManager contactManager, + MessageQueueManager messageQueueManager, + ForumManager forumManager, + ForumSharingManagerImpl forumSharingManager) { + + lifecycleManager.registerClient(forumSharingManager); + contactManager.registerAddContactHook(forumSharingManager); + contactManager.registerRemoveContactHook(forumSharingManager); + messageQueueManager.registerIncomingMessageHook( + ForumSharingManagerImpl.CLIENT_ID, forumSharingManager); + forumManager.registerRemoveForumHook(forumSharingManager); + + return forumSharingManager; + } + +} diff --git a/briar-core/src/org/briarproject/sharing/SharingSessionState.java b/briar-core/src/org/briarproject/sharing/SharingSessionState.java new file mode 100644 index 0000000000000000000000000000000000000000..6864df09ed5d7f70dc93f064aaf2a72316aaa497 --- /dev/null +++ b/briar-core/src/org/briarproject/sharing/SharingSessionState.java @@ -0,0 +1,102 @@ +package org.briarproject.sharing; + +import org.briarproject.api.FormatException; +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.MessageId; + +import static org.briarproject.api.sharing.SharingConstants.CONTACT_ID; +import static org.briarproject.api.sharing.SharingConstants.GROUP_ID; +import static org.briarproject.api.sharing.SharingConstants.IS_SHARER; +import static org.briarproject.api.sharing.SharingConstants.SESSION_ID; +import static org.briarproject.api.sharing.SharingConstants.SHAREABLE_ID; +import static org.briarproject.api.sharing.SharingConstants.STATE; +import static org.briarproject.api.sharing.SharingConstants.STORAGE_ID; + +// This class is not thread-safe +public abstract class SharingSessionState { + + private final SessionId sessionId; + private final MessageId storageId; + private final GroupId groupId; + private final ContactId contactId; + private final GroupId shareableId; + private int task = -1; // TODO get rid of task, see #376 + + public SharingSessionState(SessionId sessionId, MessageId storageId, + GroupId groupId, ContactId contactId, GroupId shareableId) { + + this.sessionId = sessionId; + this.storageId = storageId; + this.groupId = groupId; + this.contactId = contactId; + this.shareableId = shareableId; + } + + public static SharingSessionState fromBdfDictionary( + InviteeSessionStateFactory isFactory, + SharerSessionStateFactory ssFactory, BdfDictionary d) + throws FormatException { + + SessionId sessionId = new SessionId(d.getRaw(SESSION_ID)); + MessageId messageId = new MessageId(d.getRaw(STORAGE_ID)); + GroupId groupId = new GroupId(d.getRaw(GROUP_ID)); + ContactId contactId = new ContactId(d.getLong(CONTACT_ID).intValue()); + GroupId forumId = new GroupId(d.getRaw(SHAREABLE_ID)); + + int intState = d.getLong(STATE).intValue(); + if (d.getBoolean(IS_SHARER)) { + SharerSessionState.State state = + SharerSessionState.State.fromValue(intState); + return ssFactory.build(sessionId, messageId, groupId, state, + contactId, forumId, d); + } else { + InviteeSessionState.State state = + InviteeSessionState.State.fromValue(intState); + return isFactory.build(sessionId, messageId, groupId, state, + contactId, forumId, d); + } + } + + public BdfDictionary toBdfDictionary() { + BdfDictionary d = new BdfDictionary(); + d.put(SESSION_ID, getSessionId()); + d.put(STORAGE_ID, getStorageId()); + d.put(GROUP_ID, getGroupId()); + d.put(CONTACT_ID, getContactId().getInt()); + d.put(SHAREABLE_ID, getShareableId()); + + return d; + } + + public SessionId getSessionId() { + return sessionId; + } + + public MessageId getStorageId() { + return storageId; + } + + public GroupId getGroupId() { + return groupId; + } + + public ContactId getContactId() { + return contactId; + } + + public GroupId getShareableId() { + return shareableId; + } + + public void setTask(int task) { + this.task = task; + } + + public int getTask() { + return task; + } + +} \ No newline at end of file diff --git a/briar-tests/src/org/briarproject/forum/ForumSharingManagerImplTest.java b/briar-tests/src/org/briarproject/forum/SharingManagerImplTest.java similarity index 76% rename from briar-tests/src/org/briarproject/forum/ForumSharingManagerImplTest.java rename to briar-tests/src/org/briarproject/forum/SharingManagerImplTest.java index 07fc1ad80a77dacffcdf1093c7f09a954c1fffe1..bc014f56c1764e64e321e3aaa7a75bf70ed399cf 100644 --- a/briar-tests/src/org/briarproject/forum/ForumSharingManagerImplTest.java +++ b/briar-tests/src/org/briarproject/forum/SharingManagerImplTest.java @@ -5,7 +5,7 @@ import org.junit.Test; import static org.junit.Assert.fail; -public class ForumSharingManagerImplTest extends BriarTestCase { +public class SharingManagerImplTest extends BriarTestCase { @Test public void testUnitTestsExist() {