From c13eafef14b9d240c8e39f26f4cabc3d7b8197b8 Mon Sep 17 00:00:00 2001 From: Torsten Grote <t@grobox.de> Date: Wed, 4 Jan 2017 15:48:34 -0200 Subject: [PATCH] Migrate blog sharing to new sharing client infrastructure --- .../briar/api/blog/BlogConstants.java | 13 +- .../briar/api/blog/BlogInvitationRequest.java | 25 +- .../api/blog/BlogInvitationResponse.java | 8 +- .../briar/api/blog/BlogManager.java | 10 + .../briar/api/blog/BlogSharingMessage.java | 74 -- .../briar/api/forum/ForumSharingMessage.java | 79 -- .../briar/api/sharing/InvitationFactory.java | 11 - .../briar/api/sharing/SharingConstants.java | 64 - .../briar/api/sharing/SharingMessage.java | 145 --- .../briar/blog/BlogManagerImpl.java | 21 +- .../sharing/BlogInvitationFactoryImpl.java | 39 + .../sharing/BlogInviteeSessionState.java | 47 - .../briar/sharing/BlogMessageParserImpl.java | 39 + .../briar/sharing/BlogProtocolEngineImpl.java | 93 ++ .../briar/sharing/BlogSharerSessionState.java | 49 - .../briar/sharing/BlogSharingManagerImpl.java | 341 +----- .../briar/sharing/BlogSharingValidator.java | 93 +- .../InvitationReceivedEventFactory.java | 13 - ...nvitationResponseReceivedEventFactory.java | 11 - .../briar/sharing/InviteeEngine.java | 242 ---- .../briar/sharing/InviteeSessionState.java | 141 --- .../sharing/InviteeSessionStateFactory.java | 21 - .../briar/sharing/OldInvitationFactory.java | 12 - .../briar/sharing/OldSharingManagerImpl.java | 1052 ----------------- .../briar/sharing/ProtocolEngineImpl.java | 9 + .../briar/sharing/ShareableFactory.java | 27 - .../briar/sharing/SharerEngine.java | 240 ---- .../briar/sharing/SharerSessionState.java | 153 --- .../sharing/SharerSessionStateFactory.java | 22 - .../briar/sharing/SharingManagerImpl.java | 21 +- .../briar/sharing/SharingModule.java | 71 +- .../briar/sharing/SharingSessionState.java | 107 -- .../sharing/BlogSharingIntegrationTest.java | 22 +- .../sharing/BlogSharingValidatorTest.java | 185 +++ .../sharing/ForumSharingValidatorTest.java | 157 +-- .../briar/sharing/SharingValidatorTest.java | 167 +++ 36 files changed, 695 insertions(+), 3129 deletions(-) delete mode 100644 briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingMessage.java delete mode 100644 briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingMessage.java delete mode 100644 briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationFactory.java delete mode 100644 briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingMessage.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/BlogInvitationFactoryImpl.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/BlogInviteeSessionState.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/BlogMessageParserImpl.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharerSessionState.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/InvitationReceivedEventFactory.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/InvitationResponseReceivedEventFactory.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/InviteeEngine.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/InviteeSessionState.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/InviteeSessionStateFactory.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/OldInvitationFactory.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/OldSharingManagerImpl.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/ShareableFactory.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/SharerEngine.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/SharerSessionState.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/SharerSessionStateFactory.java delete mode 100644 briar-core/src/main/java/org/briarproject/briar/sharing/SharingSessionState.java create mode 100644 briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java create mode 100644 briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogConstants.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogConstants.java index 28df61f745..99c4514b26 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogConstants.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogConstants.java @@ -1,5 +1,6 @@ package org.briarproject.briar.api.blog; +import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; public interface BlogConstants { @@ -7,12 +8,7 @@ public interface BlogConstants { /** * The maximum length of a blogs's name in UTF-8 bytes. */ - int MAX_BLOG_TITLE_LENGTH = 100; - - /** - * The length of a blogs's description in UTF-8 bytes. - */ - int MAX_BLOG_DESC_LENGTH = 240; + int MAX_BLOG_NAME_LENGTH = MAX_AUTHOR_NAME_LENGTH; /** * The maximum length of a blog post's body in bytes. @@ -24,13 +20,8 @@ public interface BlogConstants { */ int MAX_BLOG_COMMENT_LENGTH = MAX_BLOG_POST_BODY_LENGTH; - /* Blog Sharing Constants */ - String BLOG_AUTHOR_NAME = "blogAuthorName"; - String BLOG_PUBLIC_KEY = "blogPublicKey"; - // Metadata keys String KEY_TYPE = "type"; - String KEY_DESCRIPTION = "description"; String KEY_TIMESTAMP = "timestamp"; String KEY_TIME_RECEIVED = "timeReceived"; String KEY_AUTHOR_ID = "id"; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java index 0618f7b088..77dddbbe03 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationRequest.java @@ -1,10 +1,7 @@ package org.briarproject.briar.api.blog; import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.identity.Author; -import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.briar.api.client.SessionId; @@ -15,24 +12,16 @@ import javax.annotation.Nullable; @NotNullByDefault public class BlogInvitationRequest extends InvitationRequest<Blog> { - private final String blogAuthorName; - - public BlogInvitationRequest(MessageId id, SessionId sessionId, - GroupId groupId, ContactId contactId, String blogAuthorName, - @Nullable String message, GroupId blogId, - boolean available, boolean canBeOpened, long time, - boolean local, boolean sent, boolean seen, boolean read) { - // TODO pass a proper blog here when redoing the BlogSharingManager - super(id, groupId, time, local, sent, seen, read, sessionId, - new Blog(new Group(blogId, BlogManager.CLIENT_ID, new byte[0]), - new Author(new AuthorId(new byte[AuthorId.LENGTH]), - blogAuthorName, new byte[0])), contactId, - message, available, canBeOpened); - this.blogAuthorName = blogAuthorName; + public BlogInvitationRequest(MessageId id, GroupId groupId, long time, + boolean local, boolean sent, boolean seen, boolean read, + SessionId sessionId, Blog blog, ContactId contactId, + @Nullable String message, boolean available, boolean canBeOpened) { + super(id, groupId, time, local, sent, seen, read, sessionId, blog, + contactId, message, available, canBeOpened); } public String getBlogAuthorName() { - return blogAuthorName; + return getShareable().getName(); } } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java index 32eaa44405..e491423002 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogInvitationResponse.java @@ -10,10 +10,10 @@ import org.briarproject.briar.api.sharing.InvitationResponse; @NotNullByDefault public class BlogInvitationResponse extends InvitationResponse { - public BlogInvitationResponse(MessageId id, SessionId sessionId, - GroupId groupId, ContactId contactId, GroupId blogId, - boolean accept, long time, boolean local, boolean sent, - boolean seen, boolean read) { + public BlogInvitationResponse(MessageId id, GroupId groupId, long time, + boolean local, boolean sent, boolean seen, boolean read, + SessionId sessionId, GroupId blogId, ContactId contactId, + boolean accept) { super(id, groupId, time, local, sent, seen, read, sessionId, blogId, contactId, accept); } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java index 8b596d6b65..20ffb991ca 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogManager.java @@ -21,6 +21,16 @@ public interface BlogManager { */ ClientId CLIENT_ID = new ClientId("org.briarproject.briar.blog"); + /** + * Adds a blog from the given author. + */ + Blog addBlog(Author author) throws DbException; + + /** + * Adds the given {@link Blog} within the given {@link Transaction}. + */ + void addBlog(Transaction txn, Blog b) throws DbException; + /** * Returns true if a blog can be removed. */ diff --git a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingMessage.java b/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingMessage.java deleted file mode 100644 index 811bf32e85..0000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/blog/BlogSharingMessage.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.briarproject.briar.api.blog; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.data.BdfList; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.api.sharing.SharingMessage.Invitation; - -import javax.annotation.Nullable; - -import static org.briarproject.briar.api.blog.BlogConstants.BLOG_AUTHOR_NAME; -import static org.briarproject.briar.api.blog.BlogConstants.BLOG_PUBLIC_KEY; -import static org.briarproject.briar.api.sharing.SharingConstants.INVITATION_MSG; -import static org.briarproject.briar.api.sharing.SharingConstants.SESSION_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.TIME; - -@NotNullByDefault -public interface BlogSharingMessage { - - class BlogInvitation extends Invitation { - - private final String blogAuthorName; - private final byte[] blogPublicKey; - - public BlogInvitation(GroupId groupId, SessionId sessionId, - String blogAuthorName, byte[] blogPublicKey, long time, - @Nullable String message) { - super(groupId, sessionId, time, message); - - this.blogAuthorName = blogAuthorName; - this.blogPublicKey = blogPublicKey; - } - - @Override - public BdfList toBdfList() { - BdfList list = super.toBdfList(); - list.add(BdfList.of(blogAuthorName, blogPublicKey)); - if (message != null) list.add(message); - return list; - } - - @Override - public BdfDictionary toBdfDictionary() { - BdfDictionary d = toBdfDictionaryHelper(); - 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 blogAuthorName = d.getString(BLOG_AUTHOR_NAME); - byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY); - String message = d.getOptionalString(INVITATION_MSG); - long time = d.getLong(TIME); - - return new BlogInvitation(groupId, sessionId, blogAuthorName, - blogPublicKey, time, message); - } - - public String getBlogAuthorName() { - return blogAuthorName; - } - - public byte[] getBlogPublicKey() { - return blogPublicKey; - } - } -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingMessage.java b/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingMessage.java deleted file mode 100644 index c8a08752e5..0000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/forum/ForumSharingMessage.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.briarproject.briar.api.forum; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.data.BdfList; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.api.sharing.SharingMessage.Invitation; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; - -import static org.briarproject.briar.api.forum.ForumConstants.FORUM_NAME; -import static org.briarproject.briar.api.forum.ForumConstants.FORUM_SALT; -import static org.briarproject.briar.api.sharing.SharingConstants.INVITATION_MSG; -import static org.briarproject.briar.api.sharing.SharingConstants.SESSION_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.TIME; - -@NotNullByDefault -public interface ForumSharingMessage { - - @Immutable - @NotNullByDefault - class ForumInvitation extends Invitation { - - private final String forumName; - private final byte[] forumSalt; - - public ForumInvitation(GroupId groupId, SessionId sessionId, - String forumName, byte[] forumSalt, long time, - @Nullable String message) { - - super(groupId, sessionId, time, message); - - this.forumName = forumName; - this.forumSalt = forumSalt; - } - - @Override - public BdfList toBdfList() { - BdfList list = super.toBdfList(); - list.add(forumName); - list.add(forumSalt); - if (message != null) list.add(message); - return list; - } - - @Override - public BdfDictionary toBdfDictionary() { - BdfDictionary d = toBdfDictionaryHelper(); - d.put(FORUM_NAME, forumName); - d.put(FORUM_SALT, forumSalt); - if (message != null) d.put(INVITATION_MSG, message); - return d; - } - - public static ForumInvitation from(GroupId groupId, BdfDictionary d) - throws FormatException { - - SessionId sessionId = new SessionId(d.getRaw(SESSION_ID)); - String forumName = d.getString(FORUM_NAME); - byte[] forumSalt = d.getRaw(FORUM_SALT); - String message = d.getOptionalString(INVITATION_MSG); - long time = d.getLong(TIME); - - return new ForumInvitation(groupId, sessionId, forumName, forumSalt, - time, message); - } - - public String getForumName() { - return forumName; - } - - public byte[] getForumSalt() { - return forumSalt; - } - } -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationFactory.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationFactory.java deleted file mode 100644 index 5b4e275a39..0000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/InvitationFactory.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.briarproject.briar.api.sharing; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.sync.GroupId; - -@Deprecated -public interface InvitationFactory<I extends SharingMessage.Invitation> { - - I build(GroupId groupId, BdfDictionary d) throws FormatException; -} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingConstants.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingConstants.java index 6b8fcc4a05..81eb45aff6 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingConstants.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingConstants.java @@ -4,74 +4,10 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_L public interface SharingConstants { - /** - * The length of a sharing session's random salt in bytes. - */ - int SHARING_SALT_LENGTH = 32; - /** * The maximum length of the optional message from the inviter to the * invitee in UTF-8 bytes. */ int MAX_INVITATION_MESSAGE_LENGTH = MAX_MESSAGE_BODY_LENGTH - 1024; - @Deprecated - String CONTACT_ID = "contactId"; - @Deprecated - String GROUP_ID = "groupId"; - @Deprecated - String TO_BE_SHARED_BY_US = "toBeSharedByUs"; - @Deprecated - String SHARED_BY_US = "sharedByUs"; - @Deprecated - String SHARED_WITH_US = "sharedWithUs"; - @Deprecated - String TYPE = "type"; - @Deprecated - String SESSION_ID = "sessionId"; - @Deprecated - String STORAGE_ID = "storageId"; - @Deprecated - String STATE = "state"; - @Deprecated - String LOCAL = "local"; - @Deprecated - String TIME = "time"; - @Deprecated - String IS_SHARER = "isSharer"; - @Deprecated - String SHAREABLE_ID = "shareableId"; - @Deprecated - String INVITATION_MSG = "invitationMsg"; - @Deprecated - String INVITATION_ID = "invitationId"; - @Deprecated - String RESPONSE_ID = "responseId"; - @Deprecated - int SHARE_MSG_TYPE_INVITATION = 1; - @Deprecated - int SHARE_MSG_TYPE_ACCEPT = 2; - @Deprecated - int SHARE_MSG_TYPE_DECLINE = 3; - @Deprecated - int SHARE_MSG_TYPE_LEAVE = 4; - @Deprecated - int SHARE_MSG_TYPE_ABORT = 5; - @Deprecated - int TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US = 0; - @Deprecated - int TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US = 1; - @Deprecated - int TASK_ADD_SHARED_SHAREABLE = 2; - @Deprecated - int TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US = 3; - @Deprecated - int TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US = 4; - @Deprecated - int TASK_SHARE_SHAREABLE = 5; - @Deprecated - int TASK_UNSHARE_SHAREABLE_SHARED_BY_US = 6; - @Deprecated - int TASK_UNSHARE_SHAREABLE_SHARED_WITH_US = 7; - } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingMessage.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingMessage.java deleted file mode 100644 index dd4b987aa9..0000000000 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingMessage.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.briarproject.briar.api.sharing; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.data.BdfEntry; -import org.briarproject.bramble.api.data.BdfList; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.briar.api.client.SessionId; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; - -import static org.briarproject.briar.api.sharing.SharingConstants.GROUP_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.SESSION_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.briar.api.sharing.SharingConstants.TIME; -import static org.briarproject.briar.api.sharing.SharingConstants.TYPE; - -@Deprecated -@NotNullByDefault -public interface SharingMessage { - - @Immutable - @NotNullByDefault - abstract class BaseMessage { - - private final GroupId groupId; - private final SessionId sessionId; - private final long time; - - BaseMessage(GroupId groupId, SessionId sessionId, long time) { - this.groupId = groupId; - this.sessionId = sessionId; - this.time = time; - } - - 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; - } - - public long getTime() { - return time; - } - } - - @Immutable - @NotNullByDefault - abstract class Invitation extends BaseMessage { - - @Nullable - protected final String message; - - public Invitation(GroupId groupId, SessionId sessionId, long time, - @Nullable String message) { - - super(groupId, sessionId, time); - - this.message = message; - } - - @Override - public long getType() { - return SHARE_MSG_TYPE_INVITATION; - } - - @Nullable - public String getMessage() { - return message; - } - } - - @Immutable - @NotNullByDefault - class SimpleMessage extends BaseMessage { - - private final long type; - - public SimpleMessage(long type, GroupId groupId, SessionId sessionId, - long time) { - super(groupId, sessionId, time); - 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)); - long time = d.getLong(TIME); - return new SimpleMessage(type, groupId, sessionId, time); - } - } - -} diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java index deab371d79..2178d42326 100644 --- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java @@ -108,7 +108,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, public void addingContact(Transaction txn, Contact c) throws DbException { // Add the personal blog of the contact and share it with the contact Blog b = blogFactory.createBlog(c.getAuthor()); - db.addGroup(txn, b.getGroup()); + addBlog(txn, b); db.setGroupVisibility(txn, c.getId(), b.getId(), SHARED); // Share our personal blog with the contact LocalAuthor a = identityManager.getLocalAuthor(txn); @@ -170,6 +170,25 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, return false; } + @Override + public Blog addBlog(Author author) throws DbException { + Blog b = blogFactory.createBlog(author); + + Transaction txn = db.startTransaction(false); + try { + db.addGroup(txn, b.getGroup()); + db.commitTransaction(txn); + } finally { + db.endTransaction(txn); + } + return b; + } + + @Override + public void addBlog(Transaction txn, Blog b) throws DbException { + db.addGroup(txn, b.getGroup()); + } + @Override public boolean canBeRemoved(GroupId g) throws DbException { Transaction txn = db.startTransaction(true); diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInvitationFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInvitationFactoryImpl.java new file mode 100644 index 0000000000..606d6fa99d --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInvitationFactoryImpl.java @@ -0,0 +1,39 @@ +package org.briarproject.briar.sharing; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.briar.api.blog.Blog; +import org.briarproject.briar.api.blog.BlogInvitationRequest; +import org.briarproject.briar.api.blog.BlogInvitationResponse; +import org.briarproject.briar.api.client.SessionId; + +import javax.inject.Inject; + +public class BlogInvitationFactoryImpl implements InvitationFactory<Blog> { + + @Inject + BlogInvitationFactoryImpl() { + } + + @Override + public BlogInvitationRequest createInvitationRequest(boolean local, + boolean sent, boolean seen, boolean read, InviteMessage<Blog> m, + ContactId c, boolean available, boolean canBeOpened) { + SessionId sessionId = new SessionId(m.getShareableId().getBytes()); + return new BlogInvitationRequest(m.getId(), m.getContactGroupId(), + m.getTimestamp(), local, sent, seen, read, sessionId, + m.getShareable(), c, m.getMessage(), available, canBeOpened); + } + + @Override + public BlogInvitationResponse createInvitationResponse(MessageId id, + GroupId contactGroupId, long time, boolean local, boolean sent, + boolean seen, boolean read, GroupId shareableId, + ContactId contactId, boolean accept) { + SessionId sessionId = new SessionId(shareableId.getBytes()); + return new BlogInvitationResponse(id, contactGroupId, time, local, + sent, seen, read, sessionId, shareableId, contactId, accept); + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInviteeSessionState.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInviteeSessionState.java deleted file mode 100644 index 564eec6cc7..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogInviteeSessionState.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; - -import javax.annotation.concurrent.NotThreadSafe; - -import static org.briarproject.briar.api.blog.BlogConstants.BLOG_AUTHOR_NAME; -import static org.briarproject.briar.api.blog.BlogConstants.BLOG_PUBLIC_KEY; - -@NotThreadSafe -@NotNullByDefault -class BlogInviteeSessionState extends InviteeSessionState { - - private final String blogAuthorName; - private final byte[] blogPublicKey; - - BlogInviteeSessionState(SessionId sessionId, MessageId storageId, - GroupId groupId, State state, ContactId contactId, GroupId blogId, - String blogAuthorName, byte[] blogPublicKey, - MessageId invitationId) { - super(sessionId, storageId, groupId, state, contactId, blogId, - invitationId); - this.blogAuthorName = blogAuthorName; - this.blogPublicKey = blogPublicKey; - } - - @Override - public BdfDictionary toBdfDictionary() { - BdfDictionary d = super.toBdfDictionary(); - d.put(BLOG_AUTHOR_NAME, getBlogAuthorName()); - d.put(BLOG_PUBLIC_KEY, getBlogPublicKey()); - return d; - } - - String getBlogAuthorName() { - return blogAuthorName; - } - - byte[] getBlogPublicKey() { - return blogPublicKey; - } -} diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogMessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogMessageParserImpl.java new file mode 100644 index 0000000000..bcf0115191 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogMessageParserImpl.java @@ -0,0 +1,39 @@ +package org.briarproject.briar.sharing; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.AuthorFactory; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.briar.api.blog.Blog; +import org.briarproject.briar.api.blog.BlogFactory; + +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +@Immutable +@NotNullByDefault +class BlogMessageParserImpl extends MessageParserImpl<Blog> { + + private final BlogFactory blogFactory; + private final AuthorFactory authorFactory; + + @Inject + BlogMessageParserImpl(ClientHelper clientHelper, BlogFactory blogFactory, + AuthorFactory authorFactory) { + super(clientHelper); + this.blogFactory = blogFactory; + this.authorFactory = authorFactory; + } + + @Override + protected Blog createShareable(BdfList descriptor) + throws FormatException { + String name = descriptor.getString(0); + byte[] publicKey = descriptor.getRaw(1); + Author author = authorFactory.createAuthor(name, publicKey); + return blogFactory.createBlog(author); + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java new file mode 100644 index 0000000000..79ba79d4a9 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogProtocolEngineImpl.java @@ -0,0 +1,93 @@ +package org.briarproject.briar.sharing; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.ClientId; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.briar.api.blog.Blog; +import org.briarproject.briar.api.blog.BlogInvitationRequest; +import org.briarproject.briar.api.blog.BlogInvitationResponse; +import org.briarproject.briar.api.blog.BlogManager; +import org.briarproject.briar.api.blog.BlogSharingManager; +import org.briarproject.briar.api.blog.event.BlogInvitationRequestReceivedEvent; +import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent; +import org.briarproject.briar.api.client.MessageTracker; + +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +@Immutable +@NotNullByDefault +class BlogProtocolEngineImpl extends ProtocolEngineImpl<Blog> { + + private final BlogManager blogManager; + private final InvitationFactory<Blog> invitationFactory; + + @Inject + BlogProtocolEngineImpl(DatabaseComponent db, + ClientHelper clientHelper, MessageEncoder messageEncoder, + MessageParser<Blog> messageParser, MessageTracker messageTracker, + Clock clock, BlogManager blogManager, + InvitationFactory<Blog> invitationFactory) { + super(db, clientHelper, messageEncoder, messageParser, messageTracker, + clock); + this.blogManager = blogManager; + this.invitationFactory = invitationFactory; + } + + @Override + Event getInvitationRequestReceivedEvent(InviteMessage<Blog> m, + ContactId contactId, boolean available, boolean canBeOpened) { + BlogInvitationRequest request = + (BlogInvitationRequest) invitationFactory + .createInvitationRequest(false, false, true, false, m, + contactId, available, canBeOpened); + return new BlogInvitationRequestReceivedEvent(m.getShareable(), + contactId, request); + } + + @Override + Event getInvitationResponseReceivedEvent(AcceptMessage m, + ContactId contactId) { + BlogInvitationResponse response = + (BlogInvitationResponse) invitationFactory + .createInvitationResponse(m.getId(), + m.getContactGroupId(), m.getTimestamp(), false, + false, true, false, m.getShareableId(), + contactId, true); + return new BlogInvitationResponseReceivedEvent(contactId, response); + } + + @Override + Event getInvitationResponseReceivedEvent(DeclineMessage m, + ContactId contactId) { + BlogInvitationResponse response = + (BlogInvitationResponse) invitationFactory + .createInvitationResponse(m.getId(), + m.getContactGroupId(), m.getTimestamp(), false, + false, true, false, m.getShareableId(), + contactId, true); + return new BlogInvitationResponseReceivedEvent(contactId, response); + } + + @Override + protected ClientId getClientId() { + return BlogSharingManager.CLIENT_ID; + } + + @Override + protected void addShareable(Transaction txn, MessageId inviteId) + throws DbException, FormatException { + InviteMessage<Blog> invite = + messageParser.getInviteMessage(txn, inviteId); + blogManager.addBlog(txn, invite.getShareable()); + } + +} diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharerSessionState.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharerSessionState.java deleted file mode 100644 index bc4b34b5e5..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharerSessionState.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.NotThreadSafe; - -import static org.briarproject.briar.api.blog.BlogConstants.BLOG_AUTHOR_NAME; -import static org.briarproject.briar.api.blog.BlogConstants.BLOG_PUBLIC_KEY; - -@NotThreadSafe -@NotNullByDefault -class BlogSharerSessionState extends SharerSessionState { - - private final String blogAuthorName; - private final byte[] blogPublicKey; - - BlogSharerSessionState(SessionId sessionId, MessageId storageId, - GroupId groupId, State state, ContactId contactId, GroupId blogId, - String blogAuthorName, byte[] blogPublicKey, - @Nullable MessageId responseId) { - super(sessionId, storageId, groupId, state, contactId, blogId, - responseId); - - this.blogAuthorName = blogAuthorName; - this.blogPublicKey = blogPublicKey; - } - - @Override - public BdfDictionary toBdfDictionary() { - BdfDictionary d = super.toBdfDictionary(); - d.put(BLOG_AUTHOR_NAME, getBlogAuthorName()); - d.put(BLOG_PUBLIC_KEY, getBlogPublicKey()); - return d; - } - - String getBlogAuthorName() { - return blogAuthorName; - } - - byte[] getBlogPublicKey() { - return blogPublicKey; - } -} diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java index a436dd9a39..9133b49174 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java @@ -1,93 +1,48 @@ package org.briarproject.briar.sharing; -import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.client.ContactGroupFactory; import org.briarproject.bramble.api.contact.Contact; -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.contact.ContactManager; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.data.BdfList; -import org.briarproject.bramble.api.data.MetadataEncoder; import org.briarproject.bramble.api.data.MetadataParser; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; -import org.briarproject.bramble.api.identity.Author; -import org.briarproject.bramble.api.identity.AuthorFactory; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.ClientId; import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.api.blog.Blog; -import org.briarproject.briar.api.blog.BlogFactory; -import org.briarproject.briar.api.blog.BlogInvitationRequest; -import org.briarproject.briar.api.blog.BlogInvitationResponse; import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.blog.BlogManager.RemoveBlogHook; import org.briarproject.briar.api.blog.BlogSharingManager; -import org.briarproject.briar.api.blog.BlogSharingMessage.BlogInvitation; -import org.briarproject.briar.api.blog.event.BlogInvitationRequestReceivedEvent; -import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent; -import org.briarproject.briar.api.client.MessageQueueManager; import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.api.sharing.InvitationMessage; -import java.security.SecureRandom; -import java.util.Collection; - -import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.briar.api.blog.BlogConstants.BLOG_AUTHOR_NAME; -import static org.briarproject.briar.api.blog.BlogConstants.BLOG_PUBLIC_KEY; -import static org.briarproject.briar.api.sharing.SharingConstants.INVITATION_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.RESPONSE_ID; - @Immutable @NotNullByDefault -class BlogSharingManagerImpl extends - OldSharingManagerImpl<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState, BlogInvitationRequestReceivedEvent, BlogInvitationResponseReceivedEvent> +class BlogSharingManagerImpl extends SharingManagerImpl<Blog> implements BlogSharingManager, RemoveBlogHook { - private final ContactManager contactManager; private final IdentityManager identityManager; 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, - ContactGroupFactory contactGroupFactory, SecureRandom random, - ContactManager contactManager, IdentityManager identityManager, - MessageTracker messageTracker) { - - super(db, messageQueueManager, clientHelper, metadataParser, - metadataEncoder, random, contactGroupFactory, messageTracker, - clock); - - this.blogManager = blogManager; - this.contactManager = contactManager; + BlogSharingManagerImpl(DatabaseComponent db, ClientHelper clientHelper, + MetadataParser metadataParser, MessageParser<Blog> messageParser, + SessionEncoder sessionEncoder, SessionParser sessionParser, + MessageTracker messageTracker, + ContactGroupFactory contactGroupFactory, + ProtocolEngine<Blog> engine, + InvitationFactory<Blog> invitationFactory, + IdentityManager identityManager, BlogManager blogManager) { + super(db, clientHelper, metadataParser, messageParser, sessionEncoder, + sessionParser, messageTracker, contactGroupFactory, engine, + invitationFactory); this.identityManager = identityManager; - sFactory = new SFactory(authorFactory, blogFactory, blogManager); - iFactory = new IFactory(); - isFactory = new ISFactory(); - ssFactory = new SSFactory(); - irFactory = new IRFactory(sFactory); - irrFactory = new IRRFactory(); + this.blogManager = blogManager; } @Override @@ -96,91 +51,18 @@ class BlogSharingManagerImpl extends } @Override - protected boolean canBeShared(Transaction txn, GroupId g, Contact c) - throws DbException { - - // check if g is our personal blog + protected boolean canBeShared(Transaction txn, GroupId shareableId, + Contact c) throws DbException { + // check if shareableId belongs to our personal blog LocalAuthor author = identityManager.getLocalAuthor(txn); Blog b = blogManager.getPersonalBlog(author); - if (b.getId().equals(g)) return false; + if (b.getId().equals(shareableId)) return false; - // check if g is c's personal blog + // check if shareableId belongs to c's personal blog b = blogManager.getPersonalBlog(c.getAuthor()); - if (b.getId().equals(g)) return false; + if (b.getId().equals(shareableId)) return false; - return super.canBeShared(txn, g, c); - } - - @Override - public Collection<Contact> getSharedWith(GroupId g) throws DbException { - Blog blog = blogManager.getBlog(g); - LocalAuthor author = identityManager.getLocalAuthor(); - if (blog.getAuthor().equals(author)) { - // This is our personal blog. It is shared with all our contacts - return contactManager.getActiveContacts(); - } else { - // This is someone else's blog. Look up who it is shared with - Collection<Contact> shared = super.getSharedWith(g); - // If the blog author is our contact, also add her to the list - boolean isContact = contactManager - .contactExists(blog.getAuthor().getId(), author.getId()); - if (isContact) { - shared.add(contactManager - .getContact(blog.getAuthor().getId(), author.getId())); - } - return shared; - } - } - - @Override - protected InvitationMessage createInvitationRequest(MessageId id, - BlogInvitation msg, ContactId contactId, GroupId blogId, - boolean available, boolean canBeOpened, long time, boolean local, - boolean sent, boolean seen, boolean read) { - - return new BlogInvitationRequest(id, msg.getSessionId(), - msg.getGroupId(), contactId, msg.getBlogAuthorName(), - msg.getMessage(), blogId, available, canBeOpened, time, local, - sent, seen, read); - } - - @Override - protected InvitationMessage createInvitationResponse(MessageId id, - SessionId sessionId, GroupId groupId, ContactId contactId, - GroupId blogId, boolean accept, long time, boolean local, - boolean sent, boolean seen, boolean read) { - return new BlogInvitationResponse(id, sessionId, groupId, contactId, - blogId, accept, time, local, sent, seen, read); - } - - @Override - protected ShareableFactory<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState> getSFactory() { - return sFactory; - } - - @Override - protected OldInvitationFactory<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, BlogInvitationRequestReceivedEvent> getIRFactory() { - return irFactory; - } - - @Override - protected InvitationResponseReceivedEventFactory<BlogSharerSessionState, BlogInvitationResponseReceivedEvent> getIRRFactory() { - return irrFactory; + return super.canBeShared(txn, shareableId, c); } @Override @@ -188,187 +70,4 @@ class BlogSharingManagerImpl extends removingShareable(txn, b); } - private static class SFactory implements - ShareableFactory<Blog, BlogInvitation, BlogInviteeSessionState, BlogSharerSessionState> { - - private final AuthorFactory authorFactory; - private final BlogFactory blogFactory; - private final BlogManager blogManager; - - private 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( - 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(0).getString(0), - shareable.getList(0).getRaw(1)); - return blogFactory.createBlog(author); - } - - @Override - public Blog parse(BlogInvitation msg) { - Author author = authorFactory.createAuthor(msg.getBlogAuthorName(), - msg.getBlogPublicKey()); - return blogFactory.createBlog(author); - } - - @Override - public Blog parse(BlogInviteeSessionState state) { - Author author = authorFactory - .createAuthor(state.getBlogAuthorName(), - state.getBlogPublicKey()); - return blogFactory.createBlog(author); - } - - @Override - public Blog parse(BlogSharerSessionState state) { - Author author = authorFactory - .createAuthor(state.getBlogAuthorName(), - state.getBlogPublicKey()); - return blogFactory.createBlog(author); - } - } - - private static class IFactory implements - OldInvitationFactory<BlogInvitation, BlogSharerSessionState> { - @Override - public BlogInvitation build(GroupId groupId, BdfDictionary d) - throws FormatException { - return BlogInvitation.from(groupId, d); - } - - @Override - public BlogInvitation build(BlogSharerSessionState localState, - long time) { - return new BlogInvitation(localState.getContactGroupId(), - localState.getSessionId(), localState.getBlogAuthorName(), - localState.getBlogPublicKey(), time, - localState.getMessage()); - } - } - - private 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 blogAuthorName = d.getString(BLOG_AUTHOR_NAME); - byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY); - MessageId invitationId = new MessageId(d.getRaw(INVITATION_ID)); - return new BlogInviteeSessionState(sessionId, storageId, - groupId, state, contactId, blogId, blogAuthorName, - blogPublicKey, invitationId); - } - - @Override - public BlogInviteeSessionState build(SessionId sessionId, - MessageId storageId, GroupId groupId, - InviteeSessionState.State state, ContactId contactId, - Blog blog, MessageId invitationId) { - return new BlogInviteeSessionState(sessionId, storageId, - groupId, state, contactId, blog.getId(), - blog.getAuthor().getName(), blog.getAuthor().getPublicKey(), - invitationId); - } - } - - private 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 blogAuthorName = d.getString(BLOG_AUTHOR_NAME); - byte[] blogPublicKey = d.getRaw(BLOG_PUBLIC_KEY); - MessageId responseId = null; - byte[] responseIdBytes = d.getOptionalRaw(RESPONSE_ID); - if (responseIdBytes != null) - responseId = new MessageId(responseIdBytes); - return new BlogSharerSessionState(sessionId, storageId, - groupId, state, contactId, blogId, blogAuthorName, - blogPublicKey, responseId); - } - - @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.getAuthor().getName(), blog.getAuthor().getPublicKey(), - null); - } - } - - private static class IRFactory implements - InvitationReceivedEventFactory<BlogInviteeSessionState, BlogInvitationRequestReceivedEvent> { - - private final SFactory sFactory; - - private IRFactory(SFactory sFactory) { - this.sFactory = sFactory; - } - - @Override - public BlogInvitationRequestReceivedEvent build( - BlogInviteeSessionState localState, long time, - @Nullable String msg) { - Blog blog = sFactory.parse(localState); - ContactId contactId = localState.getContactId(); - BlogInvitationRequest request = - new BlogInvitationRequest(localState.getInvitationId(), - localState.getSessionId(), - localState.getContactGroupId(), contactId, - blog.getAuthor().getName(), msg, - localState.getShareableId(), true, false, time, - false, false, false, false); - return new BlogInvitationRequestReceivedEvent(blog, contactId, - request); - } - } - - private static class IRRFactory implements - InvitationResponseReceivedEventFactory<BlogSharerSessionState, BlogInvitationResponseReceivedEvent> { - @Override - public BlogInvitationResponseReceivedEvent build( - BlogSharerSessionState localState, boolean accept, long time) { - ContactId c = localState.getContactId(); - MessageId responseId = localState.getResponseId(); - if (responseId == null) - throw new IllegalStateException("No responseId"); - BlogInvitationResponse response = - new BlogInvitationResponse(responseId, - localState.getSessionId(), - localState.getContactGroupId(), - localState.getContactId(), - localState.getShareableId(), accept, time, false, - false, false, false); - return new BlogInvitationResponseReceivedEvent(c, response); - } - } } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingValidator.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingValidator.java index 9dbcecd082..6f0df8e473 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingValidator.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingValidator.java @@ -1,17 +1,16 @@ package org.briarproject.briar.sharing; import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.client.BdfMessageContext; import org.briarproject.bramble.api.client.ClientHelper; -import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.MetadataEncoder; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.AuthorFactory; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.Group; -import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.system.Clock; -import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.client.BdfQueueMessageValidator; +import org.briarproject.briar.api.blog.Blog; +import org.briarproject.briar.api.blog.BlogFactory; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; @@ -20,73 +19,35 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_N import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.util.ValidationUtils.checkLength; import static org.briarproject.bramble.util.ValidationUtils.checkSize; -import static org.briarproject.briar.api.blog.BlogConstants.BLOG_AUTHOR_NAME; -import static org.briarproject.briar.api.blog.BlogConstants.BLOG_PUBLIC_KEY; -import static org.briarproject.briar.api.sharing.SharingConstants.INVITATION_MSG; -import static org.briarproject.briar.api.sharing.SharingConstants.LOCAL; -import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH; -import static org.briarproject.briar.api.sharing.SharingConstants.SESSION_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.briar.api.sharing.SharingConstants.TIME; -import static org.briarproject.briar.api.sharing.SharingConstants.TYPE; @Immutable @NotNullByDefault -class BlogSharingValidator extends BdfQueueMessageValidator { +class BlogSharingValidator extends SharingValidator { + + private final BlogFactory blogFactory; + private final AuthorFactory authorFactory; @Inject - BlogSharingValidator(ClientHelper clientHelper, - MetadataEncoder metadataEncoder, Clock clock) { - super(clientHelper, metadataEncoder, clock); + BlogSharingValidator(MessageEncoder messageEncoder, + ClientHelper clientHelper, MetadataEncoder metadataEncoder, + Clock clock, BlogFactory blogFactory, AuthorFactory authorFactory) { + super(messageEncoder, clientHelper, metadataEncoder, clock); + this.blogFactory = blogFactory; + this.authorFactory = authorFactory; } @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, 3, 4); - - BdfList author = body.getList(2); - checkSize(author, 2); - - String authorName = author.getString(0); - checkLength(authorName, 1, MAX_AUTHOR_NAME_LENGTH); - - byte[] publicKey = author.getRaw(1); - checkLength(publicKey, 1, MAX_PUBLIC_KEY_LENGTH); - - d.put(BLOG_AUTHOR_NAME, authorName); - d.put(BLOG_PUBLIC_KEY, publicKey); - - if (body.size() > 3) { - String msg = body.getString(3); - checkLength(msg, 0, MAX_INVITATION_MESSAGE_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); + protected GroupId validateDescriptor(BdfList descriptor) + throws FormatException { + checkSize(descriptor, 2); + String name = descriptor.getString(0); + checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH); + byte[] publicKey = descriptor.getRaw(1); + checkLength(publicKey, 1, MAX_PUBLIC_KEY_LENGTH); + + Author author = authorFactory.createAuthor(name, publicKey); + Blog blog = blogFactory.createBlog(author); + return blog.getId(); } + } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/InvitationReceivedEventFactory.java b/briar-core/src/main/java/org/briarproject/briar/sharing/InvitationReceivedEventFactory.java deleted file mode 100644 index 07d81557e6..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/InvitationReceivedEventFactory.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent; - -import javax.annotation.Nullable; - -@Deprecated -@NotNullByDefault -interface InvitationReceivedEventFactory<IS extends InviteeSessionState, IR extends InvitationRequestReceivedEvent> { - - IR build(IS localState, long time, @Nullable String msg); -} diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/InvitationResponseReceivedEventFactory.java b/briar-core/src/main/java/org/briarproject/briar/sharing/InvitationResponseReceivedEventFactory.java deleted file mode 100644 index 2a36e36aa5..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/InvitationResponseReceivedEventFactory.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent; - -@Deprecated -@NotNullByDefault -interface InvitationResponseReceivedEventFactory<SS extends SharerSessionState, IRR extends InvitationResponseReceivedEvent> { - - IRR build(SS localState, boolean accept, long time); -} diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/InviteeEngine.java b/briar-core/src/main/java/org/briarproject/briar/sharing/InviteeEngine.java deleted file mode 100644 index bdb0be196d..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/InviteeEngine.java +++ /dev/null @@ -1,242 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.event.Event; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.system.Clock; -import org.briarproject.briar.api.client.ProtocolEngine; -import org.briarproject.briar.api.sharing.SharingMessage.Invitation; -import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent; - -import java.util.Collections; -import java.util.List; -import java.util.logging.Logger; - -import javax.annotation.concurrent.Immutable; - -import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_ADD_SHARED_SHAREABLE; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_WITH_US; -import static org.briarproject.briar.api.sharing.SharingMessage.BaseMessage; -import static org.briarproject.briar.api.sharing.SharingMessage.SimpleMessage; - -@Deprecated -@Immutable -@NotNullByDefault -class InviteeEngine<IS extends InviteeSessionState, IR extends InvitationRequestReceivedEvent> - implements ProtocolEngine<InviteeSessionState.Action, IS, BaseMessage> { - - private static final Logger LOG = - Logger.getLogger(InviteeEngine.class.getName()); - - private final InvitationReceivedEventFactory<IS, IR> - invitationReceivedEventFactory; - private final Clock clock; - - InviteeEngine( - InvitationReceivedEventFactory<IS, IR> invitationReceivedEventFactory, - Clock clock) { - this.invitationReceivedEventFactory = invitationReceivedEventFactory; - this.clock = clock; - } - - @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.getContactGroupId(), localState.getSessionId(), - clock.currentTimeMillis()); - } else { - localState.setTask( - TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US); - msg = new SimpleMessage(SHARE_MSG_TYPE_DECLINE, - localState.getContactGroupId(), localState.getSessionId(), - clock.currentTimeMillis()); - } - messages = Collections.singletonList(msg); - logLocalAction(currentState, localState, msg); - } else if (action == InviteeSessionState.Action.LOCAL_LEAVE) { - BaseMessage msg = new SimpleMessage(SHARE_MSG_TYPE_LEAVE, - localState.getContactGroupId(), localState.getSessionId(), - clock.currentTimeMillis()); - 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); - Invitation invitation = (Invitation) msg; - Event event = invitationReceivedEventFactory.build(localState, - msg.getTime(), invitation.getMessage()); - 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.getContactGroupId(), - localState.getSessionId(), clock.currentTimeMillis()); - 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/main/java/org/briarproject/briar/sharing/InviteeSessionState.java b/briar-core/src/main/java/org/briarproject/briar/sharing/InviteeSessionState.java deleted file mode 100644 index efd35e5be8..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/InviteeSessionState.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; -import javax.annotation.concurrent.NotThreadSafe; - -import static org.briarproject.briar.api.sharing.SharingConstants.INVITATION_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.IS_SHARER; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.briar.api.sharing.SharingConstants.STATE; -import static org.briarproject.briar.sharing.InviteeSessionState.Action.LOCAL_ACCEPT; -import static org.briarproject.briar.sharing.InviteeSessionState.Action.LOCAL_DECLINE; -import static org.briarproject.briar.sharing.InviteeSessionState.Action.LOCAL_LEAVE; -import static org.briarproject.briar.sharing.InviteeSessionState.Action.REMOTE_INVITATION; -import static org.briarproject.briar.sharing.InviteeSessionState.Action.REMOTE_LEAVE; - -@Deprecated -@NotThreadSafe -@NotNullByDefault -public abstract class InviteeSessionState extends SharingSessionState { - - private State state; - private final MessageId invitationId; - - public InviteeSessionState(SessionId sessionId, MessageId storageId, - GroupId groupId, State state, ContactId contactId, - GroupId shareableId, MessageId invitationId) { - - super(sessionId, storageId, groupId, contactId, shareableId); - this.state = state; - this.invitationId = invitationId; - } - - @Override - public BdfDictionary toBdfDictionary() { - BdfDictionary d = super.toBdfDictionary(); - d.put(STATE, getState().getValue()); - d.put(IS_SHARER, false); - d.put(INVITATION_ID, invitationId); - return d; - } - - public void setState(State state) { - this.state = state; - } - - public State getState() { - return state; - } - - public MessageId getInvitationId() { - return invitationId; - } - - @Immutable - @NotNullByDefault - public enum State { - - ERROR(0), - AWAIT_INVITATION(1) { - @Override - public State next(Action a) { - if (a == REMOTE_INVITATION) return AWAIT_LOCAL_RESPONSE; - return ERROR; - } - }, - AWAIT_LOCAL_RESPONSE(2) { - @Override - public State next(Action a) { - if (a == LOCAL_ACCEPT || a == LOCAL_DECLINE) return FINISHED; - if (a == REMOTE_LEAVE) return LEFT; - return ERROR; - } - }, - FINISHED(3) { - @Override - public State next(Action a) { - if (a == LOCAL_LEAVE || a == REMOTE_LEAVE) return LEFT; - return FINISHED; - } - }, - LEFT(4) { - @Override - public State next(Action a) { - if (a == LOCAL_LEAVE) return ERROR; - return LEFT; - } - }; - - private final int value; - - State(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - - public static State fromValue(int value) { - for (State s : values()) { - if (s.value == value) return s; - } - throw new IllegalArgumentException(); - } - - public State next(Action a) { - return this; - } - } - - @NotNullByDefault - public enum Action { - - LOCAL_ACCEPT, - LOCAL_DECLINE, - LOCAL_LEAVE, - LOCAL_ABORT, - REMOTE_INVITATION, - REMOTE_LEAVE, - REMOTE_ABORT; - - @Nullable - public static Action getRemote(long type) { - if (type == SHARE_MSG_TYPE_INVITATION) return REMOTE_INVITATION; - if (type == SHARE_MSG_TYPE_LEAVE) return REMOTE_LEAVE; - if (type == SHARE_MSG_TYPE_ABORT) return REMOTE_ABORT; - return null; - } - } - -} \ No newline at end of file diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/InviteeSessionStateFactory.java b/briar-core/src/main/java/org/briarproject/briar/sharing/InviteeSessionStateFactory.java deleted file mode 100644 index 5c827921e8..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/InviteeSessionStateFactory.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.api.sharing.Shareable; - -@Deprecated -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, - MessageId invitationId); -} diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/OldInvitationFactory.java b/briar-core/src/main/java/org/briarproject/briar/sharing/OldInvitationFactory.java deleted file mode 100644 index 7f127a1c82..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/OldInvitationFactory.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.briar.api.sharing.SharingMessage; - -@Deprecated -@NotNullByDefault -interface OldInvitationFactory<I extends SharingMessage.Invitation, SS extends SharerSessionState> - extends org.briarproject.briar.api.sharing.InvitationFactory<I> { - - I build(SS localState, long time); -} diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/OldSharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/OldSharingManagerImpl.java deleted file mode 100644 index 613ee0bed8..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/OldSharingManagerImpl.java +++ /dev/null @@ -1,1052 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.Bytes; -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.client.ClientHelper; -import org.briarproject.bramble.api.client.ContactGroupFactory; -import org.briarproject.bramble.api.contact.Contact; -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.contact.ContactManager.AddContactHook; -import org.briarproject.bramble.api.contact.ContactManager.RemoveContactHook; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.data.BdfEntry; -import org.briarproject.bramble.api.data.BdfList; -import org.briarproject.bramble.api.data.MetadataEncoder; -import org.briarproject.bramble.api.data.MetadataParser; -import org.briarproject.bramble.api.db.DatabaseComponent; -import org.briarproject.bramble.api.db.DbException; -import org.briarproject.bramble.api.db.Metadata; -import org.briarproject.bramble.api.db.NoSuchMessageException; -import org.briarproject.bramble.api.db.Transaction; -import org.briarproject.bramble.api.event.Event; -import org.briarproject.bramble.api.identity.LocalAuthor; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.Client; -import org.briarproject.bramble.api.sync.ClientId; -import org.briarproject.bramble.api.sync.Group; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.Message; -import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.bramble.api.sync.MessageStatus; -import org.briarproject.bramble.api.system.Clock; -import org.briarproject.bramble.util.StringUtils; -import org.briarproject.briar.api.client.MessageQueueManager; -import org.briarproject.briar.api.client.MessageTracker; -import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.api.sharing.InvitationMessage; -import org.briarproject.briar.api.sharing.Shareable; -import org.briarproject.briar.api.sharing.SharingInvitationItem; -import org.briarproject.briar.api.sharing.SharingManager; -import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent; -import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent; -import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent; -import org.briarproject.briar.client.ConversationClientImpl; - -import java.io.IOException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Logger; - -import javax.annotation.Nullable; - -import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; -import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; -import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; -import static org.briarproject.briar.api.client.ProtocolEngine.StateUpdate; -import static org.briarproject.briar.api.sharing.SharingConstants.CONTACT_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.IS_SHARER; -import static org.briarproject.briar.api.sharing.SharingConstants.LOCAL; -import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH; -import static org.briarproject.briar.api.sharing.SharingConstants.SESSION_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.SHAREABLE_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARED_BY_US; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARED_WITH_US; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARING_SALT_LENGTH; -import static org.briarproject.briar.api.sharing.SharingConstants.STATE; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_ADD_SHARED_SHAREABLE; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_SHARE_SHAREABLE; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_BY_US; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_WITH_US; -import static org.briarproject.briar.api.sharing.SharingConstants.TIME; -import static org.briarproject.briar.api.sharing.SharingConstants.TO_BE_SHARED_BY_US; -import static org.briarproject.briar.api.sharing.SharingConstants.TYPE; -import static org.briarproject.briar.api.sharing.SharingMessage.BaseMessage; -import static org.briarproject.briar.api.sharing.SharingMessage.Invitation; -import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ; -import static org.briarproject.briar.sharing.InviteeSessionState.State.AWAIT_LOCAL_RESPONSE; - -@Deprecated -@NotNullByDefault -abstract class OldSharingManagerImpl<S extends Shareable, I extends Invitation, IS extends InviteeSessionState, SS extends SharerSessionState, IR extends InvitationRequestReceivedEvent, IRR extends InvitationResponseReceivedEvent> - extends ConversationClientImpl - implements SharingManager<S>, Client, AddContactHook, - RemoveContactHook { - - private static final Logger LOG = - Logger.getLogger(OldSharingManagerImpl.class.getName()); - - private final MessageQueueManager messageQueueManager; - private final MetadataEncoder metadataEncoder; - private final SecureRandom random; - private final ContactGroupFactory contactGroupFactory; - private final Clock clock; - private final Group localGroup; - - OldSharingManagerImpl(DatabaseComponent db, - MessageQueueManager messageQueueManager, ClientHelper clientHelper, - MetadataParser metadataParser, MetadataEncoder metadataEncoder, - SecureRandom random, ContactGroupFactory contactGroupFactory, - MessageTracker messageTracker, Clock clock) { - super(db, clientHelper, metadataParser, messageTracker); - this.messageQueueManager = messageQueueManager; - this.metadataEncoder = metadataEncoder; - this.random = random; - this.contactGroupFactory = contactGroupFactory; - this.clock = clock; - localGroup = contactGroupFactory.createLocalGroup(getClientId()); - } - - protected abstract ClientId getClientId(); - - protected abstract InvitationMessage createInvitationRequest(MessageId id, - I msg, ContactId contactId, GroupId blogId, boolean available, - boolean canBeOpened, long time, boolean local, boolean sent, - boolean seen, boolean read); - - protected abstract InvitationMessage createInvitationResponse(MessageId id, - SessionId sessionId, GroupId groupId, ContactId contactId, - GroupId blogId, boolean accept, long time, boolean local, - boolean sent, boolean seen, boolean read); - - protected abstract ShareableFactory<S, I, IS, SS> getSFactory(); - - protected abstract OldInvitationFactory<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); - // Ensure we've set things up for any pre-existing contacts - for (Contact c : db.getContacts(txn)) addingContact(txn, c); - } - - @Override - public void addingContact(Transaction txn, Contact c) throws DbException { - try { - // Create a group to share with the contact - Group g = getContactGroup(c); - // Return if we've already set things up for this contact - if (db.containsGroup(txn, g.getId())) return; - // Store the group and share it with the contact - db.addGroup(txn, g); - db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED); - // Attach the contact ID to the group - BdfDictionary meta = new BdfDictionary(); - meta.put(CONTACT_ID, c.getId().getInt()); - meta.put(TO_BE_SHARED_BY_US, new BdfList()); - meta.put(SHARED_BY_US, new BdfList()); - meta.put(SHARED_WITH_US, new BdfList()); - clientHelper.mergeGroupMetadata(txn, g.getId(), meta); - } catch (FormatException e) { - throw new DbException(e); - } - } - - @Override - public void removingContact(Transaction txn, Contact c) throws DbException { - // query for this contact c - BdfDictionary query = BdfDictionary.of( - new BdfEntry(CONTACT_ID, c.getId().getInt()) - ); - - // clean up session states with that contact from localGroup - try { - Map<MessageId, BdfDictionary> map = clientHelper - .getMessageMetadataAsDictionary(txn, localGroup.getId(), - query); - for (Map.Entry<MessageId, BdfDictionary> entry : map.entrySet()) { - deleteMessage(txn, entry.getKey()); - } - } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } - - // remove the contact group (all messages will be removed with it) - db.removeGroup(txn, getContactGroup(c)); - } - - @Override - protected boolean incomingMessage(Transaction txn, Message m, BdfList body, - BdfDictionary d) throws DbException, FormatException { - - BaseMessage msg = BaseMessage.from(getIFactory(), m.getGroupId(), d); - SessionId sessionId = msg.getSessionId(); - - if (msg.getType() == SHARE_MSG_TYPE_INVITATION) { - // we are an invitee who just received a new invitation - boolean stateExists = true; - try { - // check if we have a session with that ID already - getSessionState(txn, sessionId, false); - } catch (FormatException e) { - // this is what we would expect under normal circumstances - stateExists = false; - } - // check if we already have a state with that sessionId - if (stateExists) throw new FormatException(); - - // 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 - IS state = initializeInviteeState(txn, contactId, invitation, - m.getId()); - InviteeEngine<IS, IR> engine = - new InviteeEngine<IS, IR>(getIRFactory(), clock); - processInviteeStateUpdate(txn, m.getId(), - engine.onMessageReceived(state, msg)); - messageTracker.trackIncomingMessage(txn, m); - } else if (msg.getType() == SHARE_MSG_TYPE_ACCEPT || - msg.getType() == SHARE_MSG_TYPE_DECLINE) { - // we are a sharer who just received a response - SS state = getSessionStateForSharer(txn, sessionId); - state.setResponseId(m.getId()); - SharerEngine<I, SS, IRR> engine = - new SharerEngine<I, SS, IRR>(getIFactory(), - getIRRFactory(), clock); - processSharerStateUpdate(txn, m.getId(), - engine.onMessageReceived(state, msg)); - messageTracker.trackIncomingMessage(txn, m); - } 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 - SharingSessionState s = getSessionState(txn, sessionId, true); - if (s instanceof SharerSessionState) { - // we are a sharer and the invitee wants to leave or abort - SS state = (SS) s; - SharerEngine<I, SS, IRR> engine = - new SharerEngine<I, SS, IRR>(getIFactory(), - getIRRFactory(), clock); - processSharerStateUpdate(txn, m.getId(), - engine.onMessageReceived(state, msg)); - } else { - // we are an invitee and the sharer wants to leave or abort - IS state = (IS) s; - InviteeEngine<IS, IR> engine = - new InviteeEngine<IS, IR>(getIRFactory(), clock); - processInviteeStateUpdate(txn, m.getId(), - engine.onMessageReceived(state, msg)); - } - } else { - // message has passed validator, so that should never happen - throw new AssertionError("Illegal Sharing Message"); - } - // don't share message as other party already has it - return false; - } - - @Override - public void sendInvitation(GroupId groupId, ContactId contactId, - @Nullable String msg, long timestamp) throws DbException { - - Transaction txn = db.startTransaction(false); - try { - // initialize local state for sharer - 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)) { - int msgLength = StringUtils.toUtf8(msg).length; - if (msgLength > MAX_INVITATION_MESSAGE_LENGTH) - throw new IllegalArgumentException(); - localState.setMessage(msg); - } - - // start engine and process its state update - SharerEngine<I, SS, IRR> engine = - new SharerEngine<I, SS, IRR>(getIFactory(), - getIRRFactory(), clock); - StateUpdate<SS, BaseMessage> update = - engine.onLocalAction(localState, - SharerSessionState.Action.LOCAL_INVITATION); - processSharerStateUpdate(txn, null, update); - - // track message - // TODO handle this properly without engine hacks (#376) - long time = update.toSend.get(0).getTime(); - messageTracker.trackMessage(txn, localState.getContactGroupId(), time, - true); - - db.commitTransaction(txn); - } catch (FormatException e) { - throw new DbException(); - } finally { - db.endTransaction(txn); - } - } - - @Override - public void respondToInvitation(S f, Contact c, boolean accept) - throws DbException { - - Transaction txn = db.startTransaction(false); - try { - // find session state based on shareable - IS localState = getSessionStateForResponse(txn, f, c); - respondToInvitation(txn, localState, accept); - db.commitTransaction(txn); - } catch (FormatException e) { - throw new DbException(e); - } finally { - db.endTransaction(txn); - } - } - - @Override - public void respondToInvitation(ContactId c, SessionId id, boolean accept) - throws DbException { - - Transaction txn = db.startTransaction(false); - try { - IS localState = (IS) getSessionState(txn, id, true); - respondToInvitation(txn, localState, accept); - db.commitTransaction(txn); - } catch (FormatException e) { - throw new DbException(e); - } finally { - db.endTransaction(txn); - } - } - - private void respondToInvitation(Transaction txn, IS localState, - boolean accept) throws DbException, FormatException { - // define action - InviteeSessionState.Action localAction; - if (accept) { - localAction = InviteeSessionState.Action.LOCAL_ACCEPT; - } else { - localAction = InviteeSessionState.Action.LOCAL_DECLINE; - } - - // start engine and process its state update - InviteeEngine<IS, IR> engine = - new InviteeEngine<IS, IR>(getIRFactory(), clock); - StateUpdate<IS, BaseMessage> update = - engine.onLocalAction(localState, localAction); - processInviteeStateUpdate(txn, null, update); - - // track message - // TODO handle this properly without engine hacks (#376) - long time = update.toSend.get(0).getTime(); - messageTracker.trackMessage(txn, localState.getContactGroupId(), time, true); - } - - @Override - public Collection<InvitationMessage> getInvitationMessages( - ContactId contactId) - throws DbException { - - Transaction txn = db.startTransaction(true); - try { - Contact contact = db.getContact(txn, contactId); - Group group = getContactGroup(contact); - - Collection<InvitationMessage> list = - new ArrayList<InvitationMessage>(); - Map<MessageId, BdfDictionary> map = clientHelper - .getMessageMetadataAsDictionary(txn, group.getId()); - for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) { - BdfDictionary d = m.getValue(); - long type = d.getLong(TYPE); - if (type == SHARE_MSG_TYPE_LEAVE || - type == SHARE_MSG_TYPE_ABORT) continue; - try { - MessageStatus status = - db.getMessageStatus(txn, contactId, m.getKey()); - SharingSessionState s; - long time = d.getLong(TIME); - boolean local = d.getBoolean(LOCAL); - boolean read = d.getBoolean(MSG_KEY_READ, false); - boolean available = false, canBeOpened = false; - - if (type == SHARE_MSG_TYPE_INVITATION) { - I msg = getIFactory().build(group.getId(), d); - SessionId sessionId = msg.getSessionId(); - s = getSessionState(txn, sessionId, true); - if (!local) { - // figure out whether the shareable is still available - if (!(s instanceof InviteeSessionState)) - continue; - available = ((InviteeSessionState) s).getState() == - AWAIT_LOCAL_RESPONSE; - if (!available) { - canBeOpened = db.containsGroup(txn, - s.getShareableId()); - } - } - InvitationMessage im = - createInvitationRequest(m.getKey(), msg, - contactId, s.getShareableId(), - available, canBeOpened, time, local, - status.isSent(), status.isSeen(), read); - list.add(im); - } else if (type == SHARE_MSG_TYPE_ACCEPT || - type == SHARE_MSG_TYPE_DECLINE) { - boolean accept = type == SHARE_MSG_TYPE_ACCEPT; - BaseMessage msg = BaseMessage - .from(getIFactory(), group.getId(), d); - SessionId sessionId = msg.getSessionId(); - s = getSessionState(txn, sessionId, true); - InvitationMessage im = - createInvitationResponse(m.getKey(), sessionId, - group.getId(), contactId, - s.getShareableId(), accept, time, local, - status.isSent(), status.isSeen(), read); - list.add(im); - } else { - throw new RuntimeException("Unexpected Message Type"); - } - } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - } - } - db.commitTransaction(txn); - return list; - } catch (FormatException e) { - throw new DbException(e); - } finally { - db.endTransaction(txn); - } - } - - @Override - public Collection<SharingInvitationItem> getInvitations() - throws DbException { - List<SharingInvitationItem> invitations = - new ArrayList<SharingInvitationItem>(); - Transaction txn = db.startTransaction(true); - try { - Set<S> shareables = new HashSet<S>(); - Map<GroupId, Collection<Contact>> newSharers = - new HashMap<GroupId, Collection<Contact>>(); - Collection<Contact> contacts = db.getContacts(txn); - - // get invitations from each contact - for (Contact contact : contacts) { - Collection<S> newShareables = getInvited(txn, contact); - shareables.addAll(newShareables); - for (S s : newShareables) { - if (newSharers.containsKey(s.getId())) { - newSharers.get(s.getId()).add(contact); - } else { - Collection<Contact> c = new ArrayList<Contact>(); - c.add(contact); - newSharers.put(s.getId(), c); - } - } - } - // construct InvitationItem objects - for (S s : shareables) { - Collection<Contact> newS = newSharers.get(s.getId()); - boolean subscribed = db.containsGroup(txn, s.getId()); - SharingInvitationItem invitation = - new SharingInvitationItem(s, subscribed, newS); - invitations.add(invitation); - } - db.commitTransaction(txn); - return invitations; - } catch (FormatException e) { - throw new DbException(e); - } finally { - db.endTransaction(txn); - } - } - - private Collection<S> getInvited(Transaction txn, Contact contact) - throws DbException, FormatException { - - // query for all external invitations - BdfDictionary query = BdfDictionary.of( - new BdfEntry(TYPE, SHARE_MSG_TYPE_INVITATION), - new BdfEntry(LOCAL, false) - ); - Group group = getContactGroup(contact); - - Set<S> invited = new HashSet<S>(); - Map<MessageId, BdfDictionary> map = clientHelper - .getMessageMetadataAsDictionary(txn, group.getId(), query); - for (Map.Entry<MessageId, BdfDictionary> m : map.entrySet()) { - BdfDictionary d = m.getValue(); - try { - I msg = getIFactory().build(group.getId(), d); - IS iss = (IS) getSessionState(txn, msg.getSessionId(), true); - // get and add the shareable if the invitation is unanswered - if (iss.getState().equals(AWAIT_LOCAL_RESPONSE)) { - S s = getSFactory().parse(iss); - invited.add(s); - } - } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - } - } - return invited; - } - - @Override - public Collection<Contact> getSharedWith(GroupId g) throws DbException { - try { - List<Contact> shared = new ArrayList<Contact>(); - Transaction txn = db.startTransaction(true); - try { - for (Contact c : db.getContacts(txn)) { - GroupId contactGroup = getContactGroup(c).getId(); - if (listContains(txn, contactGroup, g, SHARED_BY_US)) - shared.add(c); - else if (listContains(txn, contactGroup, g, SHARED_WITH_US)) - shared.add(c); - } - db.commitTransaction(txn); - } finally { - db.endTransaction(txn); - } - return shared; - } catch (FormatException e) { - throw new DbException(e); - } - } - - @Override - public boolean canBeShared(GroupId g, Contact c) throws DbException { - boolean canBeShared; - Transaction txn = db.startTransaction(true); - try { - canBeShared = canBeShared(txn, g, c); - db.commitTransaction(txn); - } finally { - db.endTransaction(txn); - } - return canBeShared; - } - - protected boolean canBeShared(Transaction txn, GroupId g, Contact c) - throws DbException { - - try { - GroupId contactGroup = getContactGroup(c).getId(); - return !listContains(txn, contactGroup, g, SHARED_BY_US) && - !listContains(txn, contactGroup, g, SHARED_WITH_US) && - !listContains(txn, contactGroup, g, TO_BE_SHARED_BY_US); - } catch (FormatException e) { - throw new DbException(e); - } - } - - 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(); - if (!listContains(txn, contactGroup, f.getId(), TO_BE_SHARED_BY_US)) - // no race-condition, this invitation is invalid - throw new FormatException(); - - // we have an invitation race condition - LocalAuthor author = db.getLocalAuthor(txn, c.getLocalAuthorId()); - Bytes ourKey = new Bytes(author.getPublicKey()); - Bytes theirKey = new Bytes(c.getAuthor().getPublicKey()); - - // determine which invitation takes precedence - boolean alice = ourKey.compareTo(theirKey) < 0; - - if (alice) { - // our own invitation takes precedence, so just delete Bob's - 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."); - SharingSessionState state = - getSessionStateForLeaving(txn, f, c.getId()); - if (state instanceof SharerSessionState) { - //SharerEngine engine = new SharerEngine(); - //processSharerStateUpdate(txn, null, - // engine.onLocalAction((SharerSessionState) state, - // Action.LOCAL_LEAVE)); - - // simply remove from list instead of involving engine - removeFromList(txn, contactGroup, TO_BE_SHARED_BY_US, f); - // TODO here we could also remove the old session state - // and invitation message - } - } - - } - - private SS initializeSharerState(Transaction txn, S f, - ContactId contactId) throws FormatException, DbException { - - Contact c = db.getContact(txn, contactId); - Group group = getContactGroup(c); - - // create local message to keep engine state - long now = clock.currentTimeMillis(); - 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()); - - SS s = getSSFactory().build(sessionId, m.getId(), group.getId(), - SharerSessionState.State.PREPARE_INVITATION, contactId, f); - - // save local state to database - BdfDictionary d = s.toBdfDictionary(); - clientHelper.addLocalMessage(txn, m, d, false); - - return s; - } - - private IS initializeInviteeState(Transaction txn, - ContactId contactId, I msg, MessageId id) - throws FormatException, DbException { - - Contact c = db.getContact(txn, contactId); - Group group = getContactGroup(c); - S f = getSFactory().parse(msg); - - // create local message to keep engine state - long now = clock.currentTimeMillis(); - Bytes mSalt = new Bytes(new byte[SHARING_SALT_LENGTH]); - random.nextBytes(mSalt.getBytes()); - Message m = clientHelper.createMessage(localGroup.getId(), now, - BdfList.of(mSalt)); - - IS s = getISFactory() - .build(msg.getSessionId(), m.getId(), group.getId(), - InviteeSessionState.State.AWAIT_INVITATION, contactId, - f, id); - - // save local state to database - BdfDictionary d = s.toBdfDictionary(); - clientHelper.addLocalMessage(txn, m, d, false); - - return s; - } - - private SharingSessionState getSessionState(Transaction txn, - SessionId sessionId, boolean warn) - throws DbException, FormatException { - - try { - return getSessionStateForSharer(txn, sessionId); - } catch (NoSuchMessageException e) { - // State not found directly, so query for state for invitee - BdfDictionary query = BdfDictionary.of( - new BdfEntry(SESSION_ID, sessionId) - ); - - Map<MessageId, BdfDictionary> map = clientHelper - .getMessageMetadataAsDictionary(txn, localGroup.getId(), - query); - - if (map.size() > 1 && LOG.isLoggable(WARNING)) { - LOG.warning( - "More than one session state found for message with session ID " + - Arrays.hashCode(sessionId.getBytes())); - } - if (map.isEmpty()) { - if (warn && LOG.isLoggable(WARNING)) { - LOG.warning( - "No session state found for message with session ID " + - Arrays.hashCode(sessionId.getBytes())); - } - throw new FormatException(); - } - return SharingSessionState - .fromBdfDictionary(getISFactory(), getSSFactory(), - map.values().iterator().next()); - } - } - - private SS getSessionStateForSharer(Transaction txn, - SessionId sessionId) - throws DbException, FormatException { - - // we should be able to get the sharer state directly from sessionId - MessageId storageId = new MessageId(sessionId.getBytes()); - BdfDictionary d = - clientHelper.getMessageMetadataAsDictionary(txn, storageId); - - if (!d.getBoolean(IS_SHARER)) throw new FormatException(); - - return (SS) SharingSessionState - .fromBdfDictionary(getISFactory(), getSSFactory(), d); - } - - private IS getSessionStateForResponse(Transaction txn, - S f, Contact c) throws DbException, FormatException { - - // 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(SHAREABLE_ID, f.getId()), - new BdfEntry(STATE, AWAIT_LOCAL_RESPONSE.getValue()) - ); - - Map<MessageId, BdfDictionary> map = clientHelper - .getMessageMetadataAsDictionary(txn, localGroup.getId(), query); - - if (map.size() > 1 && LOG.isLoggable(WARNING)) { - LOG.warning( - "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()); - } - if (map.isEmpty()) { - if (LOG.isLoggable(WARNING)) { - LOG.warning( - "No session state found for shareable with ID " + - Arrays.hashCode(f.getId().getBytes()) + - " in state AWAIT_LOCAL_RESPONSE"); - } - throw new DbException(); - } - return (IS) SharingSessionState - .fromBdfDictionary(getISFactory(), getSSFactory(), - map.values().iterator().next()); - } - - private SharingSessionState getSessionStateForLeaving(Transaction txn, - S f, ContactId c) throws DbException, FormatException { - - BdfDictionary query = BdfDictionary.of( - new BdfEntry(CONTACT_ID, c.getInt()), - 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 { - SharingSessionState s = SharingSessionState - .fromBdfDictionary(getISFactory(), getSSFactory(), d); - - // check that a shareable get be left in current session - if (s instanceof SharerSessionState) { - SharerSessionState state = (SharerSessionState) s; - SharerSessionState.State nextState = - state.getState() - .next(SharerSessionState.Action.LOCAL_LEAVE); - if (nextState != SharerSessionState.State.ERROR) { - return state; - } - } else { - InviteeSessionState state = (InviteeSessionState) s; - InviteeSessionState.State nextState = state.getState() - .next(InviteeSessionState.Action.LOCAL_LEAVE); - if (nextState != InviteeSessionState.State.ERROR) { - return state; - } - } - } catch (FormatException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - } - } - throw new FormatException(); - } - - private void processStateUpdate(Transaction txn, - @Nullable MessageId messageId, - StateUpdate<SharingSessionState, BaseMessage> result, S f) - throws DbException, FormatException { - - // perform actions based on new local state - performTasks(txn, result.localState, f); - - // save new local state - MessageId storageId = result.localState.getStorageId(); - clientHelper.mergeMessageMetadata(txn, storageId, - result.localState.toBdfDictionary()); - - // send messages - for (BaseMessage msg : result.toSend) { - sendMessage(txn, msg); - } - - // broadcast events - for (Event event : result.toBroadcast) { - txn.attach(event); - } - - // delete message - if (result.deleteMessage && messageId != null) { - if (LOG.isLoggable(INFO)) { - LOG.info("Deleting message with id " + messageId.hashCode()); - } - db.deleteMessage(txn, messageId); - db.deleteMessageMetadata(txn, messageId); - } - } - - private void processSharerStateUpdate(Transaction txn, - @Nullable MessageId messageId, StateUpdate<SS, BaseMessage> result) - throws DbException, FormatException { - - StateUpdate<SharingSessionState, BaseMessage> r = - new StateUpdate<SharingSessionState, BaseMessage>( - result.deleteMessage, result.deleteState, - result.localState, result.toSend, result.toBroadcast); - - // get shareable for later - S f = getSFactory().parse(result.localState); - - processStateUpdate(txn, messageId, r, f); - } - - private void processInviteeStateUpdate(Transaction txn, - @Nullable MessageId messageId, StateUpdate<IS, BaseMessage> result) - throws DbException, FormatException { - - StateUpdate<SharingSessionState, BaseMessage> r = - new StateUpdate<SharingSessionState, BaseMessage>( - result.deleteMessage, result.deleteState, - result.localState, result.toSend, result.toBroadcast); - - // get shareable for later - S f = getSFactory().parse(result.localState); - - processStateUpdate(txn, messageId, r, f); - } - - private void performTasks(Transaction txn, SharingSessionState localState, - S f) throws FormatException, DbException { - - if (localState.getTask() == -1) return; - - // remember task and remove it from localState - long task = localState.getTask(); - localState.setTask(-1); - - // get group ID for later - GroupId groupId = localState.getContactGroupId(); - // get contact ID for later - ContactId contactId = localState.getContactId(); - - // perform tasks - if (task == TASK_ADD_SHAREABLE_TO_LIST_SHARED_WITH_US) { - addToList(txn, groupId, SHARED_WITH_US, f); - } else if (task == TASK_REMOVE_SHAREABLE_FROM_LIST_SHARED_WITH_US) { - removeFromList(txn, groupId, SHARED_WITH_US, f); - } else if (task == TASK_ADD_SHARED_SHAREABLE) { - // TODO we might want to call the add() method of the respective - // manager here, because blogs add a description for example - db.addGroup(txn, f.getGroup()); - db.setGroupVisibility(txn, contactId, f.getId(), SHARED); - } 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_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US) { - removeFromList(txn, groupId, TO_BE_SHARED_BY_US, f); - } else if (task == TASK_SHARE_SHAREABLE) { - db.setGroupVisibility(txn, contactId, f.getId(), SHARED); - removeFromList(txn, groupId, TO_BE_SHARED_BY_US, f); - addToList(txn, groupId, SHARED_BY_US, f); - } else if (task == TASK_UNSHARE_SHAREABLE_SHARED_BY_US) { - db.setGroupVisibility(txn, contactId, f.getId(), INVISIBLE); - removeFromList(txn, groupId, SHARED_BY_US, f); - // broadcast event informing UI that contact has left the group - ContactLeftShareableEvent - e = new ContactLeftShareableEvent(f.getId(), contactId); - txn.attach(e); - } else if (task == TASK_UNSHARE_SHAREABLE_SHARED_WITH_US) { - db.setGroupVisibility(txn, contactId, f.getId(), INVISIBLE); - removeFromList(txn, groupId, SHARED_WITH_US, f); - // broadcast event informing UI that contact has left the group - ContactLeftShareableEvent - e = new ContactLeftShareableEvent(f.getId(), contactId); - txn.attach(e); - } - } - - private void sendMessage(Transaction txn, BaseMessage m) - throws FormatException, DbException { - - byte[] body = clientHelper.toByteArray(m.toBdfList()); - Group group = db.getGroup(txn, m.getGroupId()); - - // add message itself as metadata - BdfDictionary d = m.toBdfDictionary(); - d.put(LOCAL, true); - d.put(TIME, m.getTime()); - Metadata meta = metadataEncoder.encode(d); - - messageQueueManager - .sendMessage(txn, group, m.getTime(), body, meta); - } - - @Override - public Group getContactGroup(Contact c) { - return contactGroupFactory.createContactGroup(getClientId(), c); - } - - private ContactId getContactId(Transaction txn, GroupId contactGroupId) - throws DbException, FormatException { - BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn, - contactGroupId); - return new ContactId(meta.getLong(CONTACT_ID).intValue()); - } - - private void leaveShareable(Transaction txn, ContactId c, S f) - throws DbException, FormatException { - - SharingSessionState state = getSessionStateForLeaving(txn, f, c); - if (state instanceof SharerSessionState) { - SharerSessionState.Action action = - SharerSessionState.Action.LOCAL_LEAVE; - SharerEngine<I, SS, IRR> engine = - new SharerEngine<I, SS, IRR>(getIFactory(), - getIRRFactory(), clock); - processSharerStateUpdate(txn, null, - engine.onLocalAction((SS) state, action)); - } else { - InviteeSessionState.Action action = - InviteeSessionState.Action.LOCAL_LEAVE; - InviteeEngine<IS, IR> engine = - new InviteeEngine<IS, IR>(getIRFactory(), clock); - processInviteeStateUpdate(txn, null, - engine.onLocalAction((IS) state, action)); - } - } - - private boolean listContains(Transaction txn, GroupId contactGroup, - GroupId shareable, String key) throws DbException, FormatException { - - 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, - S f) throws DbException, FormatException { - - 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, - S f) throws DbException, FormatException { - - List<S> shareables = getShareableList(txn, groupId, key); - if (shareables.remove(f)) { - storeShareableList(txn, groupId, key, shareables); - return true; - } - return false; - } - - 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 parseShareableList(list); - } - - private void storeShareableList(Transaction txn, GroupId groupId, - String key, - List<S> shareables) throws DbException, FormatException { - - BdfList list = encodeShareableList(shareables); - BdfDictionary metadata = BdfDictionary.of( - new BdfEntry(key, list) - ); - clientHelper.mergeGroupMetadata(txn, groupId, metadata); - } - - private BdfList encodeShareableList(List<S> shareables) { - BdfList shareableList = new BdfList(); - for (S f : shareables) - shareableList.add(getSFactory().encode(f)); - return shareableList; - } - - 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 shareable = list.getList(i); - shareables.add(getSFactory().parse(shareable)); - } - return shareables; - } - - private void deleteMessage(Transaction txn, MessageId messageId) - throws DbException { - - if (LOG.isLoggable(INFO)) - LOG.info("Deleting message with ID: " + messageId.hashCode()); - - db.deleteMessage(txn, messageId); - db.deleteMessageMetadata(txn, messageId); - } - -} diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java index dd8132d90a..ad017942a9 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/ProtocolEngineImpl.java @@ -20,6 +20,7 @@ import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.sharing.Shareable; +import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent; import java.util.Map; @@ -486,6 +487,14 @@ abstract class ProtocolEngineImpl<S extends Shareable> // The dependency, if any, must be the last remote message if (!isValidDependency(s, m.getPreviousMessageId())) return abort(txn, s); + if (s.getState() == SHARING) { + // Broadcast event informing that contact left + ContactId contactId = getContactId(txn, s.getContactGroupId()); + ContactLeftShareableEvent e = + new ContactLeftShareableEvent(s.getShareableId(), + contactId); + txn.attach(e); + } // Move to the next state return new Session(nextState, s.getContactGroupId(), s.getShareableId(), s.getLastLocalMessageId(), m.getId(), s.getLocalTimestamp(), diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/ShareableFactory.java b/briar-core/src/main/java/org/briarproject/briar/sharing/ShareableFactory.java deleted file mode 100644 index 367f8882ab..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/ShareableFactory.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.data.BdfList; -import org.briarproject.bramble.api.db.DbException; -import org.briarproject.bramble.api.db.Transaction; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.briar.api.sharing.Shareable; -import org.briarproject.briar.api.sharing.SharingMessage; - -@Deprecated -@NotNullByDefault -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/main/java/org/briarproject/briar/sharing/SharerEngine.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharerEngine.java deleted file mode 100644 index eb05d87cdf..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharerEngine.java +++ /dev/null @@ -1,240 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.event.Event; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.system.Clock; -import org.briarproject.briar.api.client.ProtocolEngine; -import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent; - -import java.util.Collections; -import java.util.List; -import java.util.logging.Logger; - -import javax.annotation.concurrent.Immutable; - -import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_ADD_SHAREABLE_TO_LIST_TO_BE_SHARED_BY_US; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_REMOVE_SHAREABLE_FROM_LIST_TO_BE_SHARED_BY_US; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_SHARE_SHAREABLE; -import static org.briarproject.briar.api.sharing.SharingConstants.TASK_UNSHARE_SHAREABLE_SHARED_BY_US; -import static org.briarproject.briar.api.sharing.SharingMessage.BaseMessage; -import static org.briarproject.briar.api.sharing.SharingMessage.Invitation; -import static org.briarproject.briar.api.sharing.SharingMessage.SimpleMessage; -import static org.briarproject.briar.sharing.SharerSessionState.Action.REMOTE_ACCEPT; -import static org.briarproject.briar.sharing.SharerSessionState.Action.REMOTE_DECLINE; - -@Deprecated -@Immutable -@NotNullByDefault -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 OldInvitationFactory<I, SS> invitationFactory; - private final InvitationResponseReceivedEventFactory<SS, IRR> - invitationResponseReceivedEventFactory; - private final Clock clock; - - SharerEngine(OldInvitationFactory<I, SS> invitationFactory, - InvitationResponseReceivedEventFactory<SS, IRR> invitationResponseReceivedEventFactory, - Clock clock) { - this.invitationFactory = invitationFactory; - this.invitationResponseReceivedEventFactory = - invitationResponseReceivedEventFactory; - this.clock = clock; - } - - @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, - clock.currentTimeMillis()); - 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.getContactGroupId(), localState.getSessionId(), - clock.currentTimeMillis()); - 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 == REMOTE_ACCEPT || action == REMOTE_DECLINE) { - if (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, action == REMOTE_ACCEPT, - msg.getTime()); - 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.getContactGroupId(), localState.getSessionId(), - clock.currentTimeMillis()); - 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/main/java/org/briarproject/briar/sharing/SharerSessionState.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharerSessionState.java deleted file mode 100644 index 2579a3f509..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharerSessionState.java +++ /dev/null @@ -1,153 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.NotThreadSafe; - -import static org.briarproject.briar.api.sharing.SharingConstants.IS_SHARER; -import static org.briarproject.briar.api.sharing.SharingConstants.RESPONSE_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ABORT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_ACCEPT; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_DECLINE; -import static org.briarproject.briar.api.sharing.SharingConstants.SHARE_MSG_TYPE_LEAVE; -import static org.briarproject.briar.api.sharing.SharingConstants.STATE; -import static org.briarproject.briar.sharing.SharerSessionState.Action.LOCAL_INVITATION; -import static org.briarproject.briar.sharing.SharerSessionState.Action.LOCAL_LEAVE; -import static org.briarproject.briar.sharing.SharerSessionState.Action.REMOTE_ACCEPT; -import static org.briarproject.briar.sharing.SharerSessionState.Action.REMOTE_DECLINE; -import static org.briarproject.briar.sharing.SharerSessionState.Action.REMOTE_LEAVE; - -@Deprecated -@NotThreadSafe -@NotNullByDefault -public abstract class SharerSessionState extends SharingSessionState { - - private State state; - @Nullable - private String msg = null; - @Nullable - private MessageId responseId; - - public SharerSessionState(SessionId sessionId, MessageId storageId, - GroupId groupId, State state, ContactId contactId, - GroupId shareableId, @Nullable MessageId responseId) { - - super(sessionId, storageId, groupId, contactId, shareableId); - this.state = state; - this.responseId = responseId; - } - - @Override - public BdfDictionary toBdfDictionary() { - BdfDictionary d = super.toBdfDictionary(); - d.put(STATE, getState().getValue()); - d.put(IS_SHARER, true); - if (responseId != null) d.put(RESPONSE_ID, responseId); - return d; - } - - public void setState(State state) { - this.state = state; - } - - public State getState() { - return state; - } - - public void setMessage(String msg) { - this.msg = msg; - } - - @Nullable - public String getMessage() { - return msg; - } - - public void setResponseId(@Nullable MessageId responseId) { - this.responseId = responseId; - } - - @Nullable - public MessageId getResponseId() { - return responseId; - } - - public enum State { - ERROR(0), - PREPARE_INVITATION(1) { - @Override - public State next(Action a) { - if (a == LOCAL_INVITATION) return AWAIT_RESPONSE; - return ERROR; - } - }, - AWAIT_RESPONSE(2) { - @Override - public State next(Action a) { - if (a == REMOTE_ACCEPT || a == REMOTE_DECLINE) return FINISHED; - if (a == LOCAL_LEAVE) return LEFT; - return ERROR; - } - }, - FINISHED(3) { - @Override - public State next(Action a) { - if (a == LOCAL_LEAVE || a == REMOTE_LEAVE) return LEFT; - return FINISHED; - } - }, - LEFT(4) { - @Override - public State next(Action a) { - if (a == LOCAL_LEAVE) return ERROR; - return LEFT; - } - }; - - private final int value; - - State(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - - public static State fromValue(int value) { - for (State s : values()) { - if (s.value == value) return s; - } - throw new IllegalArgumentException(); - } - - public State next(Action a) { - return this; - } - } - - public enum Action { - LOCAL_INVITATION, - LOCAL_LEAVE, - LOCAL_ABORT, - REMOTE_ACCEPT, - REMOTE_DECLINE, - REMOTE_LEAVE, - REMOTE_ABORT; - - public static Action getRemote(long type) { - if (type == SHARE_MSG_TYPE_ACCEPT) return REMOTE_ACCEPT; - if (type == SHARE_MSG_TYPE_DECLINE) return REMOTE_DECLINE; - if (type == SHARE_MSG_TYPE_LEAVE) return REMOTE_LEAVE; - if (type == SHARE_MSG_TYPE_ABORT) return REMOTE_ABORT; - return null; - } - } - -} \ No newline at end of file diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharerSessionStateFactory.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharerSessionStateFactory.java deleted file mode 100644 index 9be12463f7..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharerSessionStateFactory.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; -import org.briarproject.briar.api.sharing.Shareable; - -@Deprecated -@NotNullByDefault -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/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java index e0c640e1e6..4d8c60a9bc 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java @@ -23,6 +23,7 @@ import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.briar.api.client.MessageTracker; +import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.sharing.InvitationMessage; import org.briarproject.briar.api.sharing.InvitationRequest; @@ -211,8 +212,10 @@ abstract class SharingManagerImpl<S extends Shareable> SessionId sessionId = getSessionId(shareableId); Transaction txn = db.startTransaction(false); try { - // Look up the session, if there is one Contact contact = db.getContact(txn, contactId); + if (!canBeShared(txn, shareableId, contact)) + throw new ProtocolStateException(); + // Look up the session, if there is one GroupId contactGroupId = getContactGroup(contact).getId(); StoredSession ss = getSession(txn, contactGroupId, sessionId); // Create or parse the session @@ -400,12 +403,22 @@ abstract class SharingManagerImpl<S extends Shareable> @Override public boolean canBeShared(GroupId g, Contact c) throws DbException { + Transaction txn = db.startTransaction(true); + try { + boolean canBeShared = canBeShared(txn, g, c); + db.commitTransaction(txn); + return canBeShared; + } finally { + db.endTransaction(txn); + } + } + + protected boolean canBeShared(Transaction txn, GroupId g, Contact c) + throws DbException { GroupId contactGroupId = getContactGroup(c).getId(); SessionId sessionId = getSessionId(g); - Transaction txn = db.startTransaction(true); try { StoredSession ss = getSession(txn, contactGroupId, sessionId); - db.commitTransaction(txn); // If there's no session, we can share the group with the contact if (ss == null) return true; // If the session's in the right state, the contact can be invited @@ -414,8 +427,6 @@ abstract class SharingManagerImpl<S extends Shareable> return session.getState().canInvite(); } catch (FormatException e) { throw new DbException(e); - } finally { - db.endTransaction(txn); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingModule.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingModule.java index e4a24c1b73..ecd8c0f615 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingModule.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingModule.java @@ -3,12 +3,14 @@ package org.briarproject.briar.sharing; import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.data.MetadataEncoder; +import org.briarproject.bramble.api.identity.AuthorFactory; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.sync.ValidationManager; import org.briarproject.bramble.api.system.Clock; +import org.briarproject.briar.api.blog.Blog; +import org.briarproject.briar.api.blog.BlogFactory; import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.blog.BlogSharingManager; -import org.briarproject.briar.api.client.MessageQueueManager; import org.briarproject.briar.api.forum.Forum; import org.briarproject.briar.api.forum.ForumFactory; import org.briarproject.briar.api.forum.ForumManager; @@ -35,17 +37,32 @@ public class SharingModule { BlogSharingManager blogSharingManager; } + @Provides + MessageEncoder provideMessageEncoder(MessageEncoderImpl messageEncoder) { + return messageEncoder; + } + + @Provides + SessionEncoder provideSessionEncoder(SessionEncoderImpl sessionEncoder) { + return sessionEncoder; + } + + @Provides + SessionParser provideSessionParser(SessionParserImpl sessionParser) { + return sessionParser; + } + @Provides @Singleton BlogSharingValidator provideBlogSharingValidator( - MessageQueueManager messageQueueManager, ClientHelper clientHelper, - MetadataEncoder metadataEncoder, Clock clock) { - + ValidationManager validationManager, MessageEncoder messageEncoder, + ClientHelper clientHelper, MetadataEncoder metadataEncoder, + Clock clock, BlogFactory blogFactory, AuthorFactory authorFactory) { BlogSharingValidator validator = - new BlogSharingValidator(clientHelper, metadataEncoder, clock); - messageQueueManager.registerMessageValidator( - BlogSharingManager.CLIENT_ID, validator); - + new BlogSharingValidator(messageEncoder, clientHelper, + metadataEncoder, clock, blogFactory, authorFactory); + validationManager.registerMessageValidator(BlogSharingManager.CLIENT_ID, + validator); return validator; } @@ -53,14 +70,13 @@ public class SharingModule { @Singleton BlogSharingManager provideBlogSharingManager( LifecycleManager lifecycleManager, ContactManager contactManager, - MessageQueueManager messageQueueManager, + ValidationManager validationManager, ConversationManager conversationManager, BlogManager blogManager, BlogSharingManagerImpl blogSharingManager) { - lifecycleManager.registerClient(blogSharingManager); contactManager.registerAddContactHook(blogSharingManager); contactManager.registerRemoveContactHook(blogSharingManager); - messageQueueManager.registerIncomingMessageHook( + validationManager.registerIncomingMessageHook( BlogSharingManager.CLIENT_ID, blogSharingManager); conversationManager.registerConversationClient(blogSharingManager); blogManager.registerRemoveBlogHook(blogSharingManager); @@ -68,6 +84,24 @@ public class SharingModule { return blogSharingManager; } + @Provides + MessageParser<Blog> provideBlogMessageParser( + BlogMessageParserImpl blogMessageParser) { + return blogMessageParser; + } + + @Provides + ProtocolEngine<Blog> provideBlogProtocolEngine( + BlogProtocolEngineImpl blogProtocolEngine) { + return blogProtocolEngine; + } + + @Provides + InvitationFactory<Blog> provideBlogInvitationFactory( + BlogInvitationFactoryImpl blogInvitationFactory) { + return blogInvitationFactory; + } + @Provides @Singleton ForumSharingValidator provideForumSharingValidator( @@ -102,27 +136,12 @@ public class SharingModule { return forumSharingManager; } - @Provides - MessageEncoder provideMessageEncoder(MessageEncoderImpl messageEncoder) { - return messageEncoder; - } - @Provides MessageParser<Forum> provideForumMessageParser( ForumMessageParserImpl forumMessageParser) { return forumMessageParser; } - @Provides - SessionEncoder provideSessionEncoder(SessionEncoderImpl sessionEncoder) { - return sessionEncoder; - } - - @Provides - SessionParser provideSessionParser(SessionParserImpl sessionParser) { - return sessionParser; - } - @Provides ProtocolEngine<Forum> provideForumProtocolEngine( ForumProtocolEngineImpl forumProtocolEngine) { diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingSessionState.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingSessionState.java deleted file mode 100644 index 77ddbd52c4..0000000000 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingSessionState.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.briarproject.briar.sharing; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.contact.ContactId; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.sync.GroupId; -import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.api.client.SessionId; - -import javax.annotation.concurrent.NotThreadSafe; - -import static org.briarproject.briar.api.sharing.SharingConstants.CONTACT_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.GROUP_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.IS_SHARER; -import static org.briarproject.briar.api.sharing.SharingConstants.SESSION_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.SHAREABLE_ID; -import static org.briarproject.briar.api.sharing.SharingConstants.STATE; -import static org.briarproject.briar.api.sharing.SharingConstants.STORAGE_ID; - -@Deprecated -@NotThreadSafe -@NotNullByDefault -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 - - 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; - } - - 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, getContactGroupId()); - 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 getContactGroupId() { - 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-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java index 67b1a37614..5f725591f1 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java @@ -4,7 +4,6 @@ import net.jodah.concurrentunit.Waiter; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.db.DbException; -import org.briarproject.bramble.api.db.NoSuchGroupException; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; @@ -17,6 +16,7 @@ import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.blog.BlogSharingManager; import org.briarproject.briar.api.blog.event.BlogInvitationRequestReceivedEvent; import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent; +import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.sharing.InvitationMessage; import org.briarproject.briar.test.BriarIntegrationTest; import org.briarproject.briar.test.BriarIntegrationTestComponent; @@ -35,7 +35,6 @@ import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; public class BlogSharingIntegrationTest extends BriarIntegrationTest<BriarIntegrationTestComponent> { @@ -92,7 +91,7 @@ public class BlogSharingIntegrationTest injectEagerSingletons(c2); } - @Test + @Test(expected = ProtocolStateException.class) public void testPersonalBlogCannotBeSharedWithOwner() throws Exception { listenToEvents(true); @@ -109,11 +108,6 @@ public class BlogSharingIntegrationTest blogSharingManager0 .sendInvitation(blog1.getId(), contactId1From0, "Hi!", clock.currentTimeMillis()); - - // sync invitation - sync0To1(1, false); - // make sure the invitee ignored the request for their own blog - assertFalse(listener1.requestReceived); } @Test @@ -293,17 +287,11 @@ public class BlogSharingIntegrationTest assertFalse(blogSharingManager0.getSharedWith(blog2.getId()) .contains(contact1From0)); // invitee no longer has blog shared by sharer - try { - blogSharingManager1.getSharedWith(blog2.getId()); - fail(); - } catch (NoSuchGroupException e) { - // expected - } - // blog can be shared again + assertEquals(0, + blogSharingManager1.getSharedWith(blog2.getId()).size()); + // blog can be shared again by sharer assertTrue( blogSharingManager0.canBeShared(blog2.getId(), contact1From0)); - assertTrue( - blogSharingManager1.canBeShared(blog2.getId(), contact0From1)); } @Test diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java new file mode 100644 index 0000000000..c67360d648 --- /dev/null +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingValidatorTest.java @@ -0,0 +1,185 @@ +package org.briarproject.briar.sharing; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.BdfMessageContext; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.test.TestUtils; +import org.briarproject.briar.api.blog.Blog; +import org.jmock.Expectations; +import org.junit.Test; + +import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; +import static org.briarproject.bramble.test.TestUtils.getRandomId; +import static org.briarproject.briar.api.blog.BlogConstants.MAX_BLOG_NAME_LENGTH; +import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH; +import static org.briarproject.briar.sharing.MessageType.INVITE; + +public class BlogSharingValidatorTest extends SharingValidatorTest { + + private final AuthorId authorId = new AuthorId(getRandomId()); + private final String authorName = TestUtils.getRandomString(42); + private final byte[] publicKey = + TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH); + private final Author author = new Author(authorId, authorName, publicKey); + private final Blog blog = new Blog(group, author); + private final BdfList descriptor = BdfList.of(authorName, publicKey); + private final String content = + TestUtils.getRandomString(MAX_INVITATION_MESSAGE_LENGTH); + + @Override + SharingValidator getValidator() { + return new BlogSharingValidator(messageEncoder, clientHelper, + metadataEncoder, clock, blogFactory, authorFactory); + } + + @Test + public void testAcceptsInvitationWithContent() throws Exception { + expectCreateBlog(authorName, publicKey); + expectEncodeMetadata(INVITE); + BdfMessageContext messageContext = v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, descriptor, + content)); + assertExpectedContext(messageContext, previousMsgId); + } + + @Test + public void testAcceptsInvitationWithNullContent() throws Exception { + expectCreateBlog(authorName, publicKey); + expectEncodeMetadata(INVITE); + BdfMessageContext messageContext = v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, descriptor, null)); + assertExpectedContext(messageContext, previousMsgId); + } + + @Test + public void testAcceptsInvitationWithNullPreviousMsgId() throws Exception { + expectCreateBlog(authorName, publicKey); + expectEncodeMetadata(INVITE); + BdfMessageContext messageContext = v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), null, descriptor, null)); + assertExpectedContext(messageContext, null); + } + + @Test(expected = FormatException.class) + public void testRejectsNullBlogName() throws Exception { + BdfList invalidDescriptor = BdfList.of(null, publicKey); + v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, + null)); + } + + @Test(expected = FormatException.class) + public void testRejectsNonStringBlogName() throws Exception { + BdfList invalidDescriptor = BdfList.of(123, publicKey); + v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, + null)); + } + + @Test(expected = FormatException.class) + public void testRejectsTooShortBlogName() throws Exception { + BdfList invalidDescriptor = BdfList.of("", publicKey); + v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, + null)); + } + + @Test + public void testAcceptsMinLengthBlogName() throws Exception { + String shortBlogName = TestUtils.getRandomString(1); + BdfList validDescriptor = BdfList.of(shortBlogName, publicKey); + expectCreateBlog(shortBlogName, publicKey); + expectEncodeMetadata(INVITE); + BdfMessageContext messageContext = v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, validDescriptor, + null)); + assertExpectedContext(messageContext, previousMsgId); + } + + @Test(expected = FormatException.class) + public void testRejectsTooLongBlogName() throws Exception { + String invalidBlogName = + TestUtils.getRandomString(MAX_BLOG_NAME_LENGTH + 1); + BdfList invalidDescriptor = BdfList.of(invalidBlogName, publicKey); + v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, + null)); + } + + @Test(expected = FormatException.class) + public void testRejectsNullPublicKey() throws Exception { + BdfList invalidDescriptor = BdfList.of(authorName, null); + v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, + null)); + } + + @Test(expected = FormatException.class) + public void testRejectsNonRawPublicKey() throws Exception { + BdfList invalidDescriptor = BdfList.of(authorName, 123); + v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, + null)); + } + + @Test(expected = FormatException.class) + public void testRejectsTooLongPublicKey() throws Exception { + byte[] invalidKey = TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH + 1); + BdfList invalidDescriptor = BdfList.of(authorName, invalidKey); + v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, invalidDescriptor, + null)); + } + + @Test + public void testAcceptsMinLengthPublicKey() throws Exception { + byte[] key = TestUtils.getRandomBytes(1); + BdfList validDescriptor = BdfList.of(authorName, key); + + expectCreateBlog(authorName, key); + expectEncodeMetadata(INVITE); + BdfMessageContext messageContext = v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, validDescriptor, + null)); + assertExpectedContext(messageContext, previousMsgId); + } + + @Test(expected = FormatException.class) + public void testRejectsNonStringContent() throws Exception { + expectCreateBlog(authorName, publicKey); + v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, descriptor, + 123)); + } + + @Test + public void testAcceptsMinLengthContent() throws Exception { + expectCreateBlog(authorName, publicKey); + expectEncodeMetadata(INVITE); + BdfMessageContext messageContext = v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, descriptor, "1")); + assertExpectedContext(messageContext, previousMsgId); + } + + @Test(expected = FormatException.class) + public void testRejectsTooLongContent() throws Exception { + String invalidContent = + TestUtils.getRandomString(MAX_INVITATION_MESSAGE_LENGTH + 1); + expectCreateBlog(authorName, publicKey); + v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, descriptor, + invalidContent)); + } + + private void expectCreateBlog(final String name, final byte[] key) { + context.checking(new Expectations() {{ + oneOf(authorFactory).createAuthor(name, key); + will(returnValue(author)); + oneOf(blogFactory).createBlog(author); + will(returnValue(blog)); + }}); + } + +} diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingValidatorTest.java index c7d2d98f26..038da56a94 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingValidatorTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingValidatorTest.java @@ -1,45 +1,20 @@ package org.briarproject.briar.sharing; import org.briarproject.bramble.api.FormatException; -import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.client.BdfMessageContext; -import org.briarproject.bramble.api.data.BdfDictionary; -import org.briarproject.bramble.api.data.BdfEntry; import org.briarproject.bramble.api.data.BdfList; -import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.test.TestUtils; -import org.briarproject.bramble.test.ValidatorTestCase; import org.briarproject.briar.api.forum.Forum; -import org.briarproject.briar.api.forum.ForumFactory; import org.jmock.Expectations; import org.junit.Test; -import java.util.Collection; - -import javax.annotation.Nullable; - -import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.briar.api.forum.ForumConstants.FORUM_SALT_LENGTH; import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH; import static org.briarproject.briar.api.sharing.SharingConstants.MAX_INVITATION_MESSAGE_LENGTH; -import static org.briarproject.briar.sharing.MessageType.ABORT; -import static org.briarproject.briar.sharing.MessageType.ACCEPT; -import static org.briarproject.briar.sharing.MessageType.DECLINE; import static org.briarproject.briar.sharing.MessageType.INVITE; -import static org.briarproject.briar.sharing.MessageType.LEAVE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class ForumSharingValidatorTest extends ValidatorTestCase { - private final MessageEncoder messageEncoder = - context.mock(MessageEncoder.class); - private final ForumFactory forumFactory = context.mock(ForumFactory.class); - private final ForumSharingValidator v = - new ForumSharingValidator(messageEncoder, clientHelper, - metadataEncoder, clock, forumFactory); +public class ForumSharingValidatorTest extends SharingValidatorTest { - private final MessageId previousMsgId = new MessageId(getRandomId()); private final String forumName = TestUtils.getRandomString(MAX_FORUM_NAME_LENGTH); private final byte[] salt = TestUtils.getRandomBytes(FORUM_SALT_LENGTH); @@ -47,8 +22,12 @@ public class ForumSharingValidatorTest extends ValidatorTestCase { private final BdfList descriptor = BdfList.of(forumName, salt); private final String content = TestUtils.getRandomString(MAX_INVITATION_MESSAGE_LENGTH); - private final BdfDictionary meta = - BdfDictionary.of(new BdfEntry("meta", "data")); + + @Override + SharingValidator getValidator() { + return new ForumSharingValidator(messageEncoder, clientHelper, + metadataEncoder, clock, forumFactory); + } @Test public void testAcceptsInvitationWithContent() throws Exception { @@ -78,107 +57,6 @@ public class ForumSharingValidatorTest extends ValidatorTestCase { assertExpectedContext(messageContext, null); } - @Test - public void testAcceptsAccept() throws Exception { - expectEncodeMetadata(ACCEPT); - BdfMessageContext messageContext = v.validateMessage(message, group, - BdfList.of(ACCEPT.getValue(), groupId, previousMsgId)); - assertExpectedContext(messageContext, previousMsgId); - } - - @Test - public void testAcceptsDecline() throws Exception { - expectEncodeMetadata(DECLINE); - BdfMessageContext messageContext = v.validateMessage(message, group, - BdfList.of(DECLINE.getValue(), groupId, previousMsgId)); - assertExpectedContext(messageContext, previousMsgId); - } - - @Test - public void testAcceptsLeave() throws Exception { - expectEncodeMetadata(LEAVE); - BdfMessageContext messageContext = v.validateMessage(message, group, - BdfList.of(LEAVE.getValue(), groupId, previousMsgId)); - assertExpectedContext(messageContext, previousMsgId); - } - - @Test - public void testAcceptsAbort() throws Exception { - expectEncodeMetadata(ABORT); - BdfMessageContext messageContext = v.validateMessage(message, group, - BdfList.of(ABORT.getValue(), groupId, previousMsgId)); - assertExpectedContext(messageContext, previousMsgId); - } - - @Test(expected = FormatException.class) - public void testRejectsNullMessageType() throws Exception { - v.validateMessage(message, group, - BdfList.of(null, groupId, previousMsgId)); - } - - @Test(expected = FormatException.class) - public void testRejectsNonLongMessageType() throws Exception { - v.validateMessage(message, group, - BdfList.of("", groupId, previousMsgId)); - } - - @Test(expected = FormatException.class) - public void testRejectsInvalidMessageType() throws Exception { - int invalidMessageType = ABORT.getValue() + 1; - v.validateMessage(message, group, - BdfList.of(invalidMessageType, groupId, previousMsgId)); - } - - @Test(expected = FormatException.class) - public void testRejectsNullSessionId() throws Exception { - v.validateMessage(message, group, - BdfList.of(ABORT.getValue(), null, previousMsgId)); - } - - @Test(expected = FormatException.class) - public void testRejectsNonRawSessionId() throws Exception { - v.validateMessage(message, group, BdfList.of(ABORT.getValue(), 123)); - } - - @Test(expected = FormatException.class) - public void testRejectsTooShortSessionId() throws Exception { - byte[] invalidGroupId = TestUtils.getRandomBytes(UniqueId.LENGTH - 1); - v.validateMessage(message, group, - BdfList.of(ABORT.getValue(), invalidGroupId, previousMsgId)); - } - - @Test(expected = FormatException.class) - public void testRejectsTooLongSessionId() throws Exception { - byte[] invalidGroupId = TestUtils.getRandomBytes(UniqueId.LENGTH + 1); - v.validateMessage(message, group, - BdfList.of(ABORT.getValue(), invalidGroupId, previousMsgId)); - } - - @Test(expected = FormatException.class) - public void testRejectsTooShortBodyForAbort() throws Exception { - v.validateMessage(message, group, - BdfList.of(ABORT.getValue(), groupId)); - } - - @Test(expected = FormatException.class) - public void testRejectsTooLongBodyForAbort() throws Exception { - v.validateMessage(message, group, - BdfList.of(ABORT.getValue(), groupId, previousMsgId, 123)); - } - - @Test(expected = FormatException.class) - public void testRejectsTooShortBodyForInvitation() throws Exception { - v.validateMessage(message, group, - BdfList.of(INVITE.getValue(), previousMsgId, descriptor)); - } - - @Test(expected = FormatException.class) - public void testRejectsTooLongBodyForInvitation() throws Exception { - v.validateMessage(message, group, - BdfList.of(INVITE.getValue(), previousMsgId, descriptor, null, - 123)); - } - @Test(expected = FormatException.class) public void testRejectsNullForumName() throws Exception { BdfList invalidDescriptor = BdfList.of(null, salt); @@ -293,25 +171,4 @@ public class ForumSharingValidatorTest extends ValidatorTestCase { }}); } - private void expectEncodeMetadata(final MessageType type) { - context.checking(new Expectations() {{ - oneOf(messageEncoder) - .encodeMetadata(type, groupId, timestamp, false, false, - false, false); - will(returnValue(meta)); - }}); - } - - private void assertExpectedContext(BdfMessageContext messageContext, - @Nullable MessageId previousMsgId) throws FormatException { - Collection<MessageId> dependencies = messageContext.getDependencies(); - if (previousMsgId == null) { - assertTrue(dependencies.isEmpty()); - } else { - assertEquals(1, dependencies.size()); - assertTrue(dependencies.contains(previousMsgId)); - } - assertEquals(meta, messageContext.getDictionary()); - } - } diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java new file mode 100644 index 0000000000..c8e688ce1f --- /dev/null +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/SharingValidatorTest.java @@ -0,0 +1,167 @@ +package org.briarproject.briar.sharing; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.UniqueId; +import org.briarproject.bramble.api.client.BdfMessageContext; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfEntry; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.test.TestUtils; +import org.briarproject.bramble.test.ValidatorTestCase; +import org.briarproject.briar.api.blog.BlogFactory; +import org.briarproject.briar.api.forum.ForumFactory; +import org.jmock.Expectations; +import org.junit.Test; + +import java.util.Collection; + +import javax.annotation.Nullable; + +import static org.briarproject.bramble.test.TestUtils.getRandomId; +import static org.briarproject.briar.sharing.MessageType.ABORT; +import static org.briarproject.briar.sharing.MessageType.ACCEPT; +import static org.briarproject.briar.sharing.MessageType.DECLINE; +import static org.briarproject.briar.sharing.MessageType.INVITE; +import static org.briarproject.briar.sharing.MessageType.LEAVE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public abstract class SharingValidatorTest extends ValidatorTestCase { + + protected final MessageEncoder messageEncoder = + context.mock(MessageEncoder.class); + protected final ForumFactory forumFactory = + context.mock(ForumFactory.class); + protected final BlogFactory blogFactory = context.mock(BlogFactory.class); + protected final SharingValidator v = getValidator(); + + protected final MessageId previousMsgId = new MessageId(getRandomId()); + private final BdfDictionary meta = + BdfDictionary.of(new BdfEntry("meta", "data")); + + abstract SharingValidator getValidator(); + + @Test(expected = FormatException.class) + public void testRejectsTooShortBodyForInvitation() throws Exception { + v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, descriptor)); + } + + @Test(expected = FormatException.class) + public void testRejectsTooLongBodyForInvitation() throws Exception { + v.validateMessage(message, group, + BdfList.of(INVITE.getValue(), previousMsgId, descriptor, null, + 123)); + } + + @Test + public void testAcceptsAccept() throws Exception { + expectEncodeMetadata(ACCEPT); + BdfMessageContext messageContext = v.validateMessage(message, group, + BdfList.of(ACCEPT.getValue(), groupId, previousMsgId)); + assertExpectedContext(messageContext, previousMsgId); + } + + @Test + public void testAcceptsDecline() throws Exception { + expectEncodeMetadata(DECLINE); + BdfMessageContext messageContext = v.validateMessage(message, group, + BdfList.of(DECLINE.getValue(), groupId, previousMsgId)); + assertExpectedContext(messageContext, previousMsgId); + } + + @Test + public void testAcceptsLeave() throws Exception { + expectEncodeMetadata(LEAVE); + BdfMessageContext messageContext = v.validateMessage(message, group, + BdfList.of(LEAVE.getValue(), groupId, previousMsgId)); + assertExpectedContext(messageContext, previousMsgId); + } + + @Test + public void testAcceptsAbort() throws Exception { + expectEncodeMetadata(ABORT); + BdfMessageContext messageContext = v.validateMessage(message, group, + BdfList.of(ABORT.getValue(), groupId, previousMsgId)); + assertExpectedContext(messageContext, previousMsgId); + } + + @Test(expected = FormatException.class) + public void testRejectsNullMessageType() throws Exception { + v.validateMessage(message, group, + BdfList.of(null, groupId, previousMsgId)); + } + + @Test(expected = FormatException.class) + public void testRejectsNonLongMessageType() throws Exception { + v.validateMessage(message, group, + BdfList.of("", groupId, previousMsgId)); + } + + @Test(expected = FormatException.class) + public void testRejectsInvalidMessageType() throws Exception { + int invalidMessageType = ABORT.getValue() + 1; + v.validateMessage(message, group, + BdfList.of(invalidMessageType, groupId, previousMsgId)); + } + + @Test(expected = FormatException.class) + public void testRejectsNullSessionId() throws Exception { + v.validateMessage(message, group, + BdfList.of(ABORT.getValue(), null, previousMsgId)); + } + + @Test(expected = FormatException.class) + public void testRejectsNonRawSessionId() throws Exception { + v.validateMessage(message, group, BdfList.of(ABORT.getValue(), 123)); + } + + @Test(expected = FormatException.class) + public void testRejectsTooShortSessionId() throws Exception { + byte[] invalidGroupId = TestUtils.getRandomBytes(UniqueId.LENGTH - 1); + v.validateMessage(message, group, + BdfList.of(ABORT.getValue(), invalidGroupId, previousMsgId)); + } + + @Test(expected = FormatException.class) + public void testRejectsTooLongSessionId() throws Exception { + byte[] invalidGroupId = TestUtils.getRandomBytes(UniqueId.LENGTH + 1); + v.validateMessage(message, group, + BdfList.of(ABORT.getValue(), invalidGroupId, previousMsgId)); + } + + @Test(expected = FormatException.class) + public void testRejectsTooShortBodyForAbort() throws Exception { + v.validateMessage(message, group, + BdfList.of(ABORT.getValue(), groupId)); + } + + @Test(expected = FormatException.class) + public void testRejectsTooLongBodyForAbort() throws Exception { + v.validateMessage(message, group, + BdfList.of(ABORT.getValue(), groupId, previousMsgId, 123)); + } + + protected void expectEncodeMetadata(final MessageType type) { + context.checking(new Expectations() {{ + oneOf(messageEncoder) + .encodeMetadata(type, groupId, timestamp, false, false, + false, false); + will(returnValue(meta)); + }}); + } + + protected void assertExpectedContext(BdfMessageContext messageContext, + @Nullable MessageId previousMsgId) throws FormatException { + Collection<MessageId> dependencies = messageContext.getDependencies(); + if (previousMsgId == null) { + assertTrue(dependencies.isEmpty()); + } else { + assertEquals(1, dependencies.size()); + assertTrue(dependencies.contains(previousMsgId)); + } + assertEquals(meta, messageContext.getDictionary()); + } + +} -- GitLab