diff --git a/briar-core/src/org/briarproject/privategroup/invitation/CreatorProtocolEngine.java b/briar-core/src/org/briarproject/privategroup/invitation/CreatorProtocolEngine.java index 26f1715797a515b0ad8e156dbd86a8ceead788be..d31e88aa28e52dbca48d6e156ceccfe5ccc87831 100644 --- a/briar-core/src/org/briarproject/privategroup/invitation/CreatorProtocolEngine.java +++ b/briar-core/src/org/briarproject/privategroup/invitation/CreatorProtocolEngine.java @@ -27,8 +27,8 @@ import static org.briarproject.api.sync.Group.Visibility.SHARED; import static org.briarproject.privategroup.invitation.CreatorState.DISSOLVED; import static org.briarproject.privategroup.invitation.CreatorState.ERROR; import static org.briarproject.privategroup.invitation.CreatorState.INVITED; -import static org.briarproject.privategroup.invitation.CreatorState.INVITEE_JOINED; -import static org.briarproject.privategroup.invitation.CreatorState.INVITEE_LEFT; +import static org.briarproject.privategroup.invitation.CreatorState.JOINED; +import static org.briarproject.privategroup.invitation.CreatorState.LEFT; import static org.briarproject.privategroup.invitation.CreatorState.START; @Immutable @@ -55,8 +55,8 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> { case START: return onLocalInvite(txn, s, message, timestamp, signature); case INVITED: - case INVITEE_JOINED: - case INVITEE_LEFT: + case JOINED: + case LEFT: case DISSOLVED: case ERROR: throw new ProtocolStateException(); // Invalid in these states @@ -80,8 +80,8 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> { case ERROR: return s; // Ignored in these states case INVITED: - case INVITEE_JOINED: - case INVITEE_LEFT: + case JOINED: + case LEFT: return onLocalLeave(txn, s); default: throw new AssertionError(); @@ -105,8 +105,8 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> { JoinMessage m) throws DbException, FormatException { switch (s.getState()) { case START: - case INVITEE_JOINED: - case INVITEE_LEFT: + case JOINED: + case LEFT: return abort(txn, s); // Invalid in these states case INVITED: return onRemoteAccept(txn, s, m); @@ -123,11 +123,11 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> { LeaveMessage m) throws DbException, FormatException { switch (s.getState()) { case START: - case INVITEE_LEFT: + case LEFT: return abort(txn, s); // Invalid in these states case INVITED: return onRemoteDecline(txn, s, m); - case INVITEE_JOINED: + case JOINED: return onRemoteLeave(txn, s, m); case DISSOLVED: case ERROR: @@ -180,6 +180,8 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> { // The dependency, if any, must be the last remote message if (!isValidDependency(s, m.getPreviousMessageId())) return abort(txn, s); + // Send a JOIN message + Message sent = sendJoinMessage(txn, s, false); // Mark the response visible in the UI markMessageVisibleInUi(txn, m.getId(), true); // Track the message @@ -191,10 +193,10 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> { ContactId contactId = getContactId(txn, m.getContactGroupId()); txn.attach(new GroupInvitationResponseReceivedEvent(contactId, createInvitationResponse(m, contactId, true))); - // Move to the INVITEE_JOINED state + // Move to the JOINED state return new CreatorSession(s.getContactGroupId(), s.getPrivateGroupId(), - s.getLastLocalMessageId(), m.getId(), s.getLocalTimestamp(), - s.getInviteTimestamp(), INVITEE_JOINED); + sent.getId(), m.getId(), sent.getTimestamp(), + s.getInviteTimestamp(), JOINED); } private CreatorSession onRemoteDecline(Transaction txn, CreatorSession s, @@ -228,10 +230,10 @@ class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> { return abort(txn, s); // Make the private group invisible to the contact setPrivateGroupVisibility(txn, s, INVISIBLE); - // Move to the INVITEE_LEFT state + // Move to the LEFT state return new CreatorSession(s.getContactGroupId(), s.getPrivateGroupId(), s.getLastLocalMessageId(), m.getId(), s.getLocalTimestamp(), - s.getInviteTimestamp(), INVITEE_LEFT); + s.getInviteTimestamp(), LEFT); } private CreatorSession abort(Transaction txn, CreatorSession s) diff --git a/briar-core/src/org/briarproject/privategroup/invitation/CreatorState.java b/briar-core/src/org/briarproject/privategroup/invitation/CreatorState.java index 3a54b00a37bc65e52e99f303547a5360c766e5bc..a759ee7f34899d1e1d90c56e13f793de41c45424 100644 --- a/briar-core/src/org/briarproject/privategroup/invitation/CreatorState.java +++ b/briar-core/src/org/briarproject/privategroup/invitation/CreatorState.java @@ -4,8 +4,7 @@ import org.briarproject.api.FormatException; enum CreatorState implements State { - START(0), INVITED(1), INVITEE_JOINED(2), INVITEE_LEFT(3), DISSOLVED(4), - ERROR(5); + START(0), INVITED(1), JOINED(2), LEFT(3), DISSOLVED(4), ERROR(5); private final int value; diff --git a/briar-core/src/org/briarproject/privategroup/invitation/InviteeProtocolEngine.java b/briar-core/src/org/briarproject/privategroup/invitation/InviteeProtocolEngine.java index 4398badbf23598d191f182e9971a6ec37113fb1f..fe03fdb7c6ac5207fa9916905b7c28137b798b63 100644 --- a/briar-core/src/org/briarproject/privategroup/invitation/InviteeProtocolEngine.java +++ b/briar-core/src/org/briarproject/privategroup/invitation/InviteeProtocolEngine.java @@ -27,11 +27,13 @@ import javax.annotation.concurrent.Immutable; import static org.briarproject.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.api.sync.Group.Visibility.SHARED; +import static org.briarproject.api.sync.Group.Visibility.VISIBLE; +import static org.briarproject.privategroup.invitation.InviteeState.ACCEPTED; import static org.briarproject.privategroup.invitation.InviteeState.DISSOLVED; import static org.briarproject.privategroup.invitation.InviteeState.ERROR; import static org.briarproject.privategroup.invitation.InviteeState.INVITED; -import static org.briarproject.privategroup.invitation.InviteeState.INVITEE_JOINED; -import static org.briarproject.privategroup.invitation.InviteeState.INVITEE_LEFT; +import static org.briarproject.privategroup.invitation.InviteeState.JOINED; +import static org.briarproject.privategroup.invitation.InviteeState.LEFT; import static org.briarproject.privategroup.invitation.InviteeState.START; @Immutable @@ -62,8 +64,9 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> { throws DbException { switch (s.getState()) { case START: - case INVITEE_JOINED: - case INVITEE_LEFT: + case ACCEPTED: + case JOINED: + case LEFT: case DISSOLVED: case ERROR: throw new ProtocolStateException(); // Invalid in these states @@ -79,13 +82,14 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> { throws DbException { switch (s.getState()) { case START: - case INVITEE_LEFT: + case LEFT: case DISSOLVED: case ERROR: return s; // Ignored in these states case INVITED: return onLocalDecline(txn, s); - case INVITEE_JOINED: + case ACCEPTED: + case JOINED: return onLocalLeave(txn, s); default: throw new AssertionError(); @@ -105,8 +109,9 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> { case START: return onRemoteInvite(txn, s, m); case INVITED: - case INVITEE_JOINED: - case INVITEE_LEFT: + case ACCEPTED: + case JOINED: + case LEFT: case DISSOLVED: return abort(txn, s); // Invalid in these states case ERROR: @@ -119,7 +124,20 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> { @Override public InviteeSession onJoinMessage(Transaction txn, InviteeSession s, JoinMessage m) throws DbException, FormatException { - return abort(txn, s); // Invalid in this role + switch (s.getState()) { + case START: + case INVITED: + case JOINED: + case LEFT: + case DISSOLVED: + return abort(txn, s); // Invalid in these states + case ACCEPTED: + return onRemoteJoin(txn, s, m); + case ERROR: + return s; // Ignored in this state + default: + throw new AssertionError(); + } } @Override @@ -130,8 +148,9 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> { case DISSOLVED: return abort(txn, s); // Invalid in these states case INVITED: - case INVITEE_JOINED: - case INVITEE_LEFT: + case ACCEPTED: + case JOINED: + case LEFT: return onRemoteLeave(txn, s, m); case ERROR: return s; // Ignored in this state @@ -159,15 +178,15 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> { try { // Subscribe to the private group subscribeToPrivateGroup(txn, inviteId); - // Share the private group with the contact - setPrivateGroupVisibility(txn, s, SHARED); + // Make the private group visible to the contact + setPrivateGroupVisibility(txn, s, VISIBLE); } catch (FormatException e) { throw new DbException(e); // Invalid group metadata } - // Move to the INVITEE_JOINED state + // Move to the ACCEPTED state return new InviteeSession(s.getContactGroupId(), s.getPrivateGroupId(), sent.getId(), s.getLastRemoteMessageId(), sent.getTimestamp(), - s.getInviteTimestamp(), INVITEE_JOINED); + s.getInviteTimestamp(), ACCEPTED); } private InviteeSession onLocalDecline(Transaction txn, InviteeSession s) @@ -190,10 +209,10 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> { throws DbException { // Send a LEAVE message Message sent = sendLeaveMessage(txn, s, false); - // Move to the INVITEE_LEFT state + // Move to the LEFT state return new InviteeSession(s.getContactGroupId(), s.getPrivateGroupId(), sent.getId(), s.getLastRemoteMessageId(), sent.getTimestamp(), - s.getInviteTimestamp(), INVITEE_LEFT); + s.getInviteTimestamp(), LEFT); } private InviteeSession onRemoteInvite(Transaction txn, InviteeSession s, @@ -222,6 +241,25 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> { m.getTimestamp(), INVITED); } + private InviteeSession onRemoteJoin(Transaction txn, InviteeSession s, + JoinMessage m) throws DbException, FormatException { + // The timestamp must be higher than the last invite message, if any + if (m.getTimestamp() <= s.getInviteTimestamp()) return abort(txn, s); + // The dependency, if any, must be the last remote message + if (!isValidDependency(s, m.getPreviousMessageId())) + return abort(txn, s); + try { + // Share the private group with the contact + setPrivateGroupVisibility(txn, s, SHARED); + } catch (FormatException e) { + throw new DbException(e); // Invalid group metadata + } + // Move to the JOINED state + return new InviteeSession(s.getContactGroupId(), s.getPrivateGroupId(), + s.getLastLocalMessageId(), m.getId(), s.getLocalTimestamp(), + s.getInviteTimestamp(), JOINED); + } + private InviteeSession onRemoteLeave(Transaction txn, InviteeSession s, LeaveMessage m) throws DbException, FormatException { // The timestamp must be higher than the last invite message, if any diff --git a/briar-core/src/org/briarproject/privategroup/invitation/InviteeState.java b/briar-core/src/org/briarproject/privategroup/invitation/InviteeState.java index 97e6480a5d04a9b16846b8580fc55b19e1e34f6c..3299d747ea9c759f04e8fd8d740805e01fc885ca 100644 --- a/briar-core/src/org/briarproject/privategroup/invitation/InviteeState.java +++ b/briar-core/src/org/briarproject/privategroup/invitation/InviteeState.java @@ -4,8 +4,8 @@ import org.briarproject.api.FormatException; enum InviteeState implements State { - START(0), INVITED(1), INVITEE_JOINED(2), INVITEE_LEFT(3), DISSOLVED(4), - ERROR(5); + START(0), INVITED(1), ACCEPTED(2), JOINED(3), LEFT(4), DISSOLVED(5), + ERROR(6); private final int value; diff --git a/briar-core/src/org/briarproject/privategroup/invitation/PeerProtocolEngine.java b/briar-core/src/org/briarproject/privategroup/invitation/PeerProtocolEngine.java index 06b019649ea27b23d6f3f6e0baedc0f5cf1cc5fc..7eaebba496d456f507577d9354a6db3e36fe7242 100644 --- a/briar-core/src/org/briarproject/privategroup/invitation/PeerProtocolEngine.java +++ b/briar-core/src/org/briarproject/privategroup/invitation/PeerProtocolEngine.java @@ -22,6 +22,7 @@ import javax.annotation.concurrent.Immutable; import static org.briarproject.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.api.sync.Group.Visibility.SHARED; +import static org.briarproject.api.sync.Group.Visibility.VISIBLE; import static org.briarproject.privategroup.invitation.PeerState.AWAIT_MEMBER; import static org.briarproject.privategroup.invitation.PeerState.BOTH_JOINED; import static org.briarproject.privategroup.invitation.PeerState.ERROR; @@ -169,6 +170,12 @@ class PeerProtocolEngine extends AbstractProtocolEngine<PeerSession> { PeerSession s) throws DbException { // Send a JOIN message Message sent = sendJoinMessage(txn, s, false); + try { + // Make the private group visible to the contact + setPrivateGroupVisibility(txn, s, VISIBLE); + } catch (FormatException e) { + throw new DbException(e); // Invalid group metadata + } // Move to the LOCAL_JOINED state return new PeerSession(s.getContactGroupId(), s.getPrivateGroupId(), sent.getId(), s.getLastRemoteMessageId(), sent.getTimestamp(), @@ -212,6 +219,12 @@ class PeerProtocolEngine extends AbstractProtocolEngine<PeerSession> { PeerSession s) throws DbException { // Send a LEAVE message Message sent = sendLeaveMessage(txn, s, false); + try { + // Make the private group invisible to the contact + setPrivateGroupVisibility(txn, s, INVISIBLE); + } catch (FormatException e) { + throw new DbException(e); // Invalid group metadata + } // Move to the NEITHER_JOINED state return new PeerSession(s.getContactGroupId(), s.getPrivateGroupId(), sent.getId(), s.getLastRemoteMessageId(), sent.getTimestamp(), @@ -316,8 +329,8 @@ class PeerProtocolEngine extends AbstractProtocolEngine<PeerSession> { // The dependency, if any, must be the last remote message if (!isValidDependency(s, m.getPreviousMessageId())) return abort(txn, s); - // Make the private group invisible to the contact - setPrivateGroupVisibility(txn, s, INVISIBLE); + // Unshare the private group with the contact + setPrivateGroupVisibility(txn, s, VISIBLE); // Move to the LOCAL_JOINED state return new PeerSession(s.getContactGroupId(), s.getPrivateGroupId(), s.getLastLocalMessageId(), m.getId(), s.getLocalTimestamp(),