From 429bbe1275f5d4d8e274d79fdaf05e8715eb8efd Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 16 Jan 2023 14:44:13 -0300 Subject: [PATCH] Introduce more sharing states --- .../SelectableContactHolder.java | 10 +++++++-- briar-android/src/main/res/values/strings.xml | 4 +++- .../invitation/GroupInvitationManager.java | 2 ++ .../briar/api/sharing/SharingManager.java | 21 +++++++++++++++---- .../GroupInvitationManagerImpl.java | 12 ++++++++++- .../briar/sharing/SharingManagerImpl.java | 19 +++++++++++++---- .../org/briarproject/briar/sharing/State.java | 8 ------- .../GroupInvitationIntegrationTest.java | 6 +++--- .../GroupInvitationManagerImplTest.java | 19 +++++++++++------ .../sharing/ForumSharingIntegrationTest.java | 11 +++++++--- 10 files changed, 80 insertions(+), 32 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contactselection/SelectableContactHolder.java b/briar-android/src/main/java/org/briarproject/briar/android/contactselection/SelectableContactHolder.java index 21d5c7c52..85df76122 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contactselection/SelectableContactHolder.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contactselection/SelectableContactHolder.java @@ -13,7 +13,9 @@ import androidx.annotation.UiThread; import static android.view.View.GONE; import static android.view.View.VISIBLE; -import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITED; +import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.ERROR; +import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITE_RECEIVED; +import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITE_SENT; import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.NOT_SUPPORTED; import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHARING; @@ -35,10 +37,14 @@ class SelectableContactHolder @StringRes int strRes; if (item.getSharingStatus() == SHARING) { strRes = R.string.forum_invitation_already_sharing; - } else if (item.getSharingStatus() == INVITED) { + } else if (item.getSharingStatus() == INVITE_SENT) { strRes = R.string.forum_invitation_already_invited; + } else if (item.getSharingStatus() == INVITE_RECEIVED) { + strRes = R.string.forum_invitation_invite_received; } else if (item.getSharingStatus() == NOT_SUPPORTED) { strRes = R.string.forum_invitation_not_supported; + } else if (item.getSharingStatus() == ERROR) { + strRes = R.string.forum_invitation_error; } else throw new AssertionError("Unhandled SharingStatus"); info.setText(strRes); info.setVisibility(VISIBLE); diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 3f6d4a93a..97fec719f 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -461,8 +461,10 @@ Invitation declined Shared by %s Already sharing - Already invited + Invitation already sent + Invitation already received Not supported by this contact + Error. This is a bug and not your fault You accepted the forum invitation from %s. You declined the forum invitation from %s. The forum invitation from %s was automatically declined. diff --git a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java index fc0feb5b0..73a60db14 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/privategroup/invitation/GroupInvitationManager.java @@ -84,6 +84,8 @@ public interface GroupInvitationManager extends ConversationClient { * and {@link PrivateGroup} identified by the given {@link GroupId}. * This indicates whether the {@link PrivateGroup} can be shared * with the contact. + * + * @throws ProtocolStateException if {@link PrivateGroup} was already left. */ SharingStatus getSharingStatus(Contact c, GroupId g) throws DbException; } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java b/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java index aa0e5202f..023419126 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/sharing/SharingManager.java @@ -5,6 +5,7 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.conversation.ConversationManager.ConversationClient; import org.briarproject.nullsafety.NotNullByDefault; @@ -24,10 +25,14 @@ public interface SharingManager SHAREABLE, /** * The {@link Shareable} can not be shared with the requested contact, - * because of an ongoing sharing session. - * In most cases, this means that the contact was already invited. + * because the contact was already invited. */ - INVITED, + INVITE_SENT, + /** + * The {@link Shareable} can not be shared with the requested contact, + * because the contact has already invited us. + */ + INVITE_RECEIVED, /** * The {@link Shareable} can not be shared with the requested contact, * because it is already being shared. @@ -38,7 +43,11 @@ public interface SharingManager * because it is not supported by that contact. * This could be a missing or outdated client. */ - NOT_SUPPORTED + NOT_SUPPORTED, + /** + * The sharing session has encountered an error. + */ + ERROR } /** @@ -106,6 +115,8 @@ public interface SharingManager * and {@link Shareable} identified by the given {@link GroupId}. * This indicates whether the {@link Shareable} can be shared * with the contact. + * + * @throws ProtocolStateException if {@link Shareable} was already left. */ SharingStatus getSharingStatus(GroupId g, Contact c) throws DbException; @@ -114,6 +125,8 @@ public interface SharingManager * and {@link Shareable} identified by the given {@link GroupId}. * This indicates whether the {@link Shareable} can be shared * with the contact. + * + * @throws ProtocolStateException if {@link Shareable} was already left. */ SharingStatus getSharingStatus(Transaction txn, GroupId g, Contact c) throws DbException; diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java index 4f1ca7e9b..0373ad2da 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java @@ -26,6 +26,7 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; import org.briarproject.briar.api.autodelete.event.ConversationMessagesDeletedEvent; 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.conversation.ConversationMessageHeader; import org.briarproject.briar.api.conversation.DeletionResult; @@ -57,6 +58,9 @@ import javax.inject.Inject; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.validation.IncomingMessageHook.DeliveryAction.ACCEPT_DO_NOT_SHARE; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER; +import static org.briarproject.briar.privategroup.invitation.CreatorState.DISSOLVED; +import static org.briarproject.briar.privategroup.invitation.CreatorState.ERROR; +import static org.briarproject.briar.privategroup.invitation.CreatorState.INVITED; import static org.briarproject.briar.privategroup.invitation.CreatorState.JOINED; import static org.briarproject.briar.privategroup.invitation.CreatorState.START; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; @@ -533,8 +537,14 @@ class GroupInvitationManagerImpl extends ConversationClientImpl .parseCreatorSession(contactGroupId, ss.bdfSession); CreatorState state = session.getState(); if (state == START) return SharingStatus.SHAREABLE; + if (state == INVITED) return SharingStatus.INVITE_RECEIVED; if (state == JOINED) return SharingStatus.SHARING; - return SharingStatus.INVITED; + // The creator can also be a LEFT state, after re-adding a contact + // and re-creating the session with #recreateSession() + if (state == CreatorState.LEFT) return SharingStatus.SHARING; + if (state == DISSOLVED) throw new ProtocolStateException(); + if (state == ERROR) return SharingStatus.ERROR; + throw new AssertionError("Unhandled state: " + state.name()); } catch (FormatException e) { throw new DbException(e); } finally { 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 a7c6854a3..b34b9965e 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 @@ -26,6 +26,7 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; import org.briarproject.briar.api.autodelete.event.ConversationMessagesDeletedEvent; 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.conversation.ConversationMessageHeader; import org.briarproject.briar.api.conversation.ConversationRequest; @@ -58,7 +59,11 @@ 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.briarproject.briar.sharing.State.LOCAL_INVITED; +import static org.briarproject.briar.sharing.State.LOCAL_LEFT; +import static org.briarproject.briar.sharing.State.REMOTE_HANGING; +import static org.briarproject.briar.sharing.State.REMOTE_INVITED; import static org.briarproject.briar.sharing.State.SHARING; +import static org.briarproject.briar.sharing.State.START; @NotNullByDefault abstract class SharingManagerImpl @@ -468,7 +473,8 @@ abstract class SharingManagerImpl } @Override - public SharingStatus getSharingStatus(GroupId g, Contact c) throws DbException { + public SharingStatus getSharingStatus(GroupId g, Contact c) + throws DbException { Transaction txn = db.startTransaction(true); try { SharingStatus sharingStatus = getSharingStatus(txn, g, c); @@ -495,9 +501,14 @@ abstract class SharingManagerImpl // If the session's in the right state, the contact can be invited Session session = sessionParser.parseSession(contactGroupId, ss.bdfSession); - if (session.getState().canInvite()) return SharingStatus.SHAREABLE; - if (session.getState().isSharing()) return SharingStatus.SHARING; - return SharingStatus.INVITED; + State state = session.getState(); + if (state == START) return SharingStatus.SHAREABLE; + if (state == LOCAL_INVITED) return SharingStatus.INVITE_RECEIVED; + if (state == REMOTE_INVITED) return SharingStatus.INVITE_SENT; + if (state == SHARING) return SharingStatus.SHARING; + if (state == LOCAL_LEFT || state == REMOTE_HANGING) + throw new ProtocolStateException(); + throw new AssertionError("Unhandled state: " + state.name()); } catch (FormatException e) { throw new DbException(e); } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/State.java b/briar-core/src/main/java/org/briarproject/briar/sharing/State.java index 1f4bba1fd..d1703048e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/State.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/State.java @@ -46,14 +46,6 @@ enum State { return visibility; } - public boolean canInvite() { - return this == START; - } - - public boolean isSharing() { - return this == SHARING; - } - public boolean isAwaitingResponse() { return this == LOCAL_INVITED || this == REMOTE_INVITED; } diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java index de7209497..5db86bea8 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationIntegrationTest.java @@ -29,7 +29,7 @@ import javax.annotation.Nullable; import static java.util.Collections.emptySet; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; -import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITED; +import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITE_RECEIVED; import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHAREABLE; import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHARING; import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount; @@ -322,7 +322,7 @@ public class GroupInvitationIntegrationTest sendInvitation(c0.getClock().currentTimeMillis(), null); // invitation is not allowed before the first hasn't been answered - assertEquals(INVITED, groupInvitationManager0 + assertEquals(INVITE_RECEIVED, groupInvitationManager0 .getSharingStatus(contact1From0, privateGroup.getId())); // deliver invitation and response @@ -740,7 +740,7 @@ public class GroupInvitationIntegrationTest addDefaultContacts(); // creator can still not invite again - assertEquals(INVITED, groupInvitationManager0 + assertEquals(SHARING, groupInvitationManager0 .getSharingStatus(contact1From0, privateGroup.getId())); // finally invitee can remove group without issues diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java index aaa445f63..8f3c2398c 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java @@ -25,6 +25,7 @@ import org.briarproject.bramble.test.DbExpectations; import org.briarproject.bramble.test.TestUtils; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.SessionId; +import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.conversation.ConversationMessageHeader; import org.briarproject.briar.api.privategroup.PrivateGroup; import org.briarproject.briar.api.privategroup.PrivateGroupFactory; @@ -62,7 +63,8 @@ import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROU import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID; import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.MAJOR_VERSION; -import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITED; +import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.ERROR; +import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITE_RECEIVED; import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHAREABLE; import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHARING; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; @@ -880,15 +882,20 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { @Test public void testIsNotInvitationAllowed() throws Exception { expectIsInvitationAllowed(CreatorState.DISSOLVED); - assertEquals(INVITED, groupInvitationManager - .getSharingStatus(contact, privateGroup.getId())); + try { + groupInvitationManager + .getSharingStatus(contact, privateGroup.getId()); + fail(); + } catch (ProtocolStateException e) { + // expected + } expectIsInvitationAllowed(CreatorState.ERROR); - assertEquals(INVITED, groupInvitationManager + assertEquals(ERROR, groupInvitationManager .getSharingStatus(contact, privateGroup.getId())); expectIsInvitationAllowed(CreatorState.INVITED); - assertEquals(INVITED, groupInvitationManager + assertEquals(INVITE_RECEIVED, groupInvitationManager .getSharingStatus(contact, privateGroup.getId())); expectIsInvitationAllowed(CreatorState.JOINED); @@ -896,7 +903,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { .getSharingStatus(contact, privateGroup.getId())); expectIsInvitationAllowed(CreatorState.LEFT); - assertEquals(INVITED, groupInvitationManager + assertEquals(SHARING, groupInvitationManager .getSharingStatus(contact, privateGroup.getId())); } diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java index bf0a799a7..b4d0a1bce 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/ForumSharingIntegrationTest.java @@ -13,6 +13,7 @@ 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.test.TestDatabaseConfigModule; +import org.briarproject.briar.api.client.ProtocolStateException; import org.briarproject.briar.api.conversation.ConversationMessageHeader; import org.briarproject.briar.api.conversation.ConversationResponse; import org.briarproject.briar.api.conversation.DeletionResult; @@ -43,11 +44,11 @@ import javax.annotation.Nullable; import static java.util.Collections.emptySet; import static junit.framework.Assert.assertNotNull; +import static junit.framework.TestCase.fail; import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS; import static org.briarproject.briar.api.forum.ForumSharingManager.CLIENT_ID; import static org.briarproject.briar.api.forum.ForumSharingManager.MAJOR_VERSION; -import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.INVITED; import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHAREABLE; import static org.briarproject.briar.api.sharing.SharingManager.SharingStatus.SHARING; import static org.briarproject.briar.test.BriarTestUtils.assertGroupCount; @@ -349,8 +350,12 @@ public class ForumSharingIntegrationTest assertEquals(SHAREABLE, forumSharingManager0 .getSharingStatus(forum.getId(), contact1From0)); // invitee that left can not yet share again - assertEquals(INVITED, forumSharingManager1 - .getSharingStatus(forum.getId(), contact0From1)); + try { + forumSharingManager1.getSharingStatus(forum.getId(), contact0From1); + fail(); + } catch (ProtocolStateException e) { + // expected + } // sharer responds with leave message sync0To1(1, true);