mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Merge branch '709-reveal-relationships' into 'master'
Mark relationship visible when syncing group with peer This branch updates the private group invitation protocol to use @grote's new method for marking a contact relationship visible to the group. I've changed the method slightly because the protocol state machine allows us to leave and re-enter the BOTH_JOINED state (see diagram on #659), so the relationship may already be visible when the method is called. In that case the visibility isn't updated, so we stick with whichever of revealed-by-us and revealed-by-contact happened first. See merge request !402
This commit is contained in:
2
.idea/codeStyleSettings.xml
generated
2
.idea/codeStyleSettings.xml
generated
@@ -31,6 +31,8 @@
|
||||
</value>
|
||||
</option>
|
||||
<option name="RIGHT_MARGIN" value="100" />
|
||||
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
|
||||
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
|
||||
<AndroidXmlCodeStyleSettings>
|
||||
<option name="USE_CUSTOM_SETTINGS" value="true" />
|
||||
</AndroidXmlCodeStyleSettings>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.briarproject.api.privategroup.invitation;
|
||||
|
||||
import org.briarproject.api.clients.ProtocolStateException;
|
||||
import org.briarproject.api.clients.SessionId;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
@@ -26,22 +27,41 @@ public interface GroupInvitationManager {
|
||||
/**
|
||||
* Sends an invitation to share the given private group with the given
|
||||
* contact, including an optional message.
|
||||
*
|
||||
* @throws ProtocolStateException if the group is no longer eligible to be
|
||||
* shared with the contact, for example because an invitation is already
|
||||
* pending.
|
||||
*/
|
||||
void sendInvitation(GroupId g, ContactId c, @Nullable String message,
|
||||
long timestamp, byte[] signature) throws DbException;
|
||||
|
||||
/**
|
||||
* Responds to a pending private group invitation from the given contact.
|
||||
*
|
||||
* @throws ProtocolStateException if the invitation is no longer pending,
|
||||
* for example because the group has been dissolved.
|
||||
*/
|
||||
void respondToInvitation(ContactId c, PrivateGroup g, boolean accept)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Responds to a pending private group invitation from the given contact.
|
||||
*
|
||||
* @throws ProtocolStateException if the invitation is no longer pending,
|
||||
* for example because the group has been dissolved.
|
||||
*/
|
||||
void respondToInvitation(ContactId c, SessionId s, boolean accept)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Makes the user's relationship with the given contact visible to the
|
||||
* given private group.
|
||||
*
|
||||
* @throws ProtocolStateException if the relationship is no longer eligible
|
||||
* to be revealed, for example because the contact has revealed it.
|
||||
*/
|
||||
void revealRelationship(ContactId c, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all private group invitation messages related to the given
|
||||
* contact.
|
||||
|
||||
@@ -443,21 +443,26 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn, g);
|
||||
BdfList members = meta.getList(GROUP_KEY_MEMBERS);
|
||||
Visibility v = INVISIBLE;
|
||||
boolean foundMember = false;
|
||||
boolean foundMember = false, changed = false;
|
||||
for (int i = 0 ; i < members.size(); i++) {
|
||||
BdfDictionary d = members.getDictionary(i);
|
||||
AuthorId memberId = new AuthorId(d.getRaw(KEY_MEMBER_ID));
|
||||
if (a.equals(memberId)) {
|
||||
foundMember = true;
|
||||
Visibility vOld = getVisibility(d);
|
||||
if (vOld != INVISIBLE) throw new ProtocolStateException();
|
||||
v = byContact ? REVEALED_BY_CONTACT : REVEALED_BY_US;
|
||||
d.put(GROUP_KEY_VISIBILITY, v.getInt());
|
||||
// Don't update the visibility if the contact is already visible
|
||||
if (getVisibility(d) == INVISIBLE) {
|
||||
changed = true;
|
||||
v = byContact ? REVEALED_BY_CONTACT : REVEALED_BY_US;
|
||||
d.put(GROUP_KEY_VISIBILITY, v.getInt());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundMember) throw new ProtocolStateException();
|
||||
clientHelper.mergeGroupMetadata(txn, g, meta);
|
||||
txn.attach(new ContactRelationshipRevealedEvent(g, v));
|
||||
if (changed) {
|
||||
clientHelper.mergeGroupMetadata(txn, g, meta);
|
||||
txn.attach(new ContactRelationshipRevealedEvent(g, v));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -315,6 +315,30 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revealRelationship(ContactId c, GroupId g) throws DbException {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
// Look up the session
|
||||
Contact contact = db.getContact(txn, c);
|
||||
GroupId contactGroupId = getContactGroup(contact).getId();
|
||||
StoredSession ss = getSession(txn, contactGroupId, getSessionId(g));
|
||||
if (ss == null) throw new IllegalArgumentException();
|
||||
// Parse the session
|
||||
PeerSession session = sessionParser
|
||||
.parsePeerSession(contactGroupId, ss.bdfSession);
|
||||
// Handle the join action
|
||||
session = peerEngine.onJoinAction(txn, session);
|
||||
// Store the updated session
|
||||
storeSession(txn, ss.storageId, session);
|
||||
db.commitTransaction(txn);
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
}
|
||||
|
||||
private <S extends Session> S handleAction(Transaction txn,
|
||||
LocalAction type, S session, ProtocolEngine<S> engine)
|
||||
throws DbException, FormatException {
|
||||
@@ -435,9 +459,6 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
||||
db.commitTransaction(txn);
|
||||
// If there's no session, the contact can be invited
|
||||
if (ss == null) return true;
|
||||
// If there's a session, it should be a creator session
|
||||
if (sessionParser.getRole(ss.bdfSession) != CREATOR)
|
||||
throw new IllegalArgumentException();
|
||||
// If the session's in the start state, the contact can be invited
|
||||
CreatorSession session = sessionParser
|
||||
.parseCreatorSession(contactGroupId, ss.bdfSession);
|
||||
|
||||
@@ -3,6 +3,8 @@ package org.briarproject.privategroup.invitation;
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.clients.ClientHelper;
|
||||
import org.briarproject.api.clients.ProtocolStateException;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.Transaction;
|
||||
@@ -179,6 +181,7 @@ class PeerProtocolEngine extends AbstractProtocolEngine<PeerSession> {
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e); // Invalid group metadata
|
||||
}
|
||||
// The relationship is already marked visible to the group
|
||||
// Move to the BOTH_JOINED state
|
||||
return new PeerSession(s.getContactGroupId(), s.getPrivateGroupId(),
|
||||
sent.getId(), s.getLastRemoteMessageId(), sent.getTimestamp(),
|
||||
@@ -228,6 +231,12 @@ class PeerProtocolEngine extends AbstractProtocolEngine<PeerSession> {
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e); // Invalid group metadata
|
||||
}
|
||||
try {
|
||||
// Mark the relationship visible to the group, revealed by contact
|
||||
relationshipRevealed(txn, s, true);
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e); // Invalid group metadata
|
||||
}
|
||||
// Move to the BOTH_JOINED state
|
||||
return new PeerSession(s.getContactGroupId(), s.getPrivateGroupId(),
|
||||
sent.getId(), s.getLastRemoteMessageId(), sent.getTimestamp(),
|
||||
@@ -254,6 +263,8 @@ class PeerProtocolEngine extends AbstractProtocolEngine<PeerSession> {
|
||||
Message sent = sendJoinMessage(txn, s, false);
|
||||
// Start syncing the private group with the contact
|
||||
syncPrivateGroupWithContact(txn, s, true);
|
||||
// Mark the relationship visible to the group, revealed by contact
|
||||
relationshipRevealed(txn, s, true);
|
||||
// Move to the BOTH_JOINED state
|
||||
return new PeerSession(s.getContactGroupId(), s.getPrivateGroupId(),
|
||||
sent.getId(), m.getId(), sent.getTimestamp(), BOTH_JOINED);
|
||||
@@ -266,6 +277,8 @@ class PeerProtocolEngine extends AbstractProtocolEngine<PeerSession> {
|
||||
return abort(txn, s);
|
||||
// Start syncing the private group with the contact
|
||||
syncPrivateGroupWithContact(txn, s, true);
|
||||
// Mark the relationship visible to the group, revealed by us
|
||||
relationshipRevealed(txn, s, false);
|
||||
// Move to the BOTH_JOINED state
|
||||
return new PeerSession(s.getContactGroupId(), s.getPrivateGroupId(),
|
||||
s.getLastLocalMessageId(), m.getId(), s.getLocalTimestamp(),
|
||||
@@ -321,4 +334,12 @@ class PeerProtocolEngine extends AbstractProtocolEngine<PeerSession> {
|
||||
sent.getId(), s.getLastRemoteMessageId(), sent.getTimestamp(),
|
||||
ERROR);
|
||||
}
|
||||
|
||||
private void relationshipRevealed(Transaction txn, PeerSession s,
|
||||
boolean byContact) throws DbException, FormatException {
|
||||
ContactId contactId = getContactId(txn, s.getContactGroupId());
|
||||
Contact contact = db.getContact(txn, contactId);
|
||||
privateGroupManager.relationshipRevealed(txn, s.getPrivateGroupId(),
|
||||
contact.getAuthor().getId(), byContact);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user