mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Recreate plausible private group sharing sessions when re-adding contact from group
This commit is contained in:
@@ -110,9 +110,9 @@ public interface PrivateGroupManager {
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the private group with the given ID was created by us.
|
||||
* Returns true if the given private group was created by us.
|
||||
*/
|
||||
boolean isOurPrivateGroup(Transaction txn, GroupId g) throws DbException;
|
||||
boolean isOurPrivateGroup(Transaction txn, PrivateGroup g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the text of the private group message with the given ID.
|
||||
|
||||
@@ -287,11 +287,10 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOurPrivateGroup(Transaction txn, GroupId g)
|
||||
public boolean isOurPrivateGroup(Transaction txn, PrivateGroup g)
|
||||
throws DbException {
|
||||
PrivateGroup group = getPrivateGroup(txn, g);
|
||||
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
|
||||
return localAuthor.getId().equals(group.getCreator().getId());
|
||||
return localAuthor.getId().equals(g.getCreator().getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -126,20 +126,60 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
||||
db.setGroupVisibility(txn, c.getId(), g.getId(), client);
|
||||
// Attach the contact ID to the group
|
||||
clientHelper.setContactId(txn, g.getId(), c.getId());
|
||||
// If the contact belongs to any private groups (we didn't create),
|
||||
// create a peer session
|
||||
for (Group pg : db.getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||
// If the contact belongs to any private groups, create a peer session
|
||||
// or sessions in LEFT state for creator/invitee.
|
||||
for (Group group : db.getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||
PrivateGroupManager.MAJOR_VERSION)) {
|
||||
if (privateGroupManager.isMember(txn, pg.getId(), c.getAuthor())) {
|
||||
if (!privateGroupManager.isOurPrivateGroup(txn, pg.getId())) {
|
||||
addingMember(txn, pg.getId(), c);
|
||||
}
|
||||
if (privateGroupManager
|
||||
.isMember(txn, group.getId(), c.getAuthor())) {
|
||||
PrivateGroup pg =
|
||||
privateGroupManager.getPrivateGroup(txn, group.getId());
|
||||
recreateSession(txn, c, pg, g.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void recreateSession(Transaction txn, Contact c,
|
||||
PrivateGroup pg, GroupId contactGroupId) throws DbException {
|
||||
boolean isOur = privateGroupManager.isOurPrivateGroup(txn, pg);
|
||||
boolean isTheirs =
|
||||
c.getAuthor().getId().equals(pg.getCreator().getId());
|
||||
if (isOur || isTheirs) {
|
||||
// we are creator or invitee, create a left session for each role
|
||||
MessageId storageId = createStorageId(txn, contactGroupId);
|
||||
Session<?> session;
|
||||
if (isOur) {
|
||||
session = new CreatorSession(contactGroupId, pg.getId(), null,
|
||||
null, 0, 0, CreatorState.LEFT);
|
||||
} else {
|
||||
session = new InviteeSession(contactGroupId, pg.getId(), null,
|
||||
null, 0, 0, InviteeState.LEFT);
|
||||
}
|
||||
try {
|
||||
storeSession(txn, storageId, session);
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
} else {
|
||||
// we are neither creator nor invitee, create peer session
|
||||
addingMember(txn, pg.getId(), c);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removingContact(Transaction txn, Contact c) throws DbException {
|
||||
// mark private groups created by that contact as dissolved
|
||||
for (Group g : db.getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||
PrivateGroupManager.MAJOR_VERSION)) {
|
||||
if (privateGroupManager.isMember(txn, g.getId(), c.getAuthor())) {
|
||||
PrivateGroup pg =
|
||||
privateGroupManager.getPrivateGroup(txn, g.getId());
|
||||
// check if contact to be removed is creator of the group
|
||||
if (c.getAuthor().getId().equals(pg.getCreator().getId())) {
|
||||
privateGroupManager.markGroupDissolved(txn, g.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove the contact group (all messages will be removed with it)
|
||||
db.removeGroup(txn, getContactGroup(c));
|
||||
}
|
||||
|
||||
@@ -722,15 +722,26 @@ public class GroupInvitationIntegrationTest
|
||||
sync0To1(2, true); // + one invitation protocol join message
|
||||
sync1To0(1, true);
|
||||
|
||||
// inviting again is not possible
|
||||
assertFalse(groupInvitationManager0
|
||||
.isInvitationAllowed(contact1From0, privateGroup.getId()));
|
||||
|
||||
// re-add contacts
|
||||
// contacts remove each other
|
||||
removeAllContacts();
|
||||
|
||||
// group gets dissolved for invitee automatically, but not creator
|
||||
assertFalse(groupManager0.isDissolved(privateGroup.getId()));
|
||||
assertTrue(groupManager1.isDissolved(privateGroup.getId()));
|
||||
|
||||
// contacts re-add each other
|
||||
addDefaultContacts();
|
||||
|
||||
assertTrue(groupInvitationManager0
|
||||
// creator can still not invite again
|
||||
assertFalse(groupInvitationManager0
|
||||
.isInvitationAllowed(contact1From0, privateGroup.getId()));
|
||||
|
||||
// finally invitee can remove group without issues
|
||||
groupManager1.removePrivateGroup(privateGroup.getId());
|
||||
}
|
||||
|
||||
private Collection<ConversationMessageHeader> getMessages1From0()
|
||||
|
||||
@@ -45,6 +45,8 @@ import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static junit.framework.TestCase.fail;
|
||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
||||
@@ -105,7 +107,9 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
||||
private final ContactId contactId = contact.getId();
|
||||
private final Group localGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||
private final Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||
private final Group privateGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||
private final Group group = getGroup(CLIENT_ID, MAJOR_VERSION);
|
||||
private final PrivateGroup privateGroup = new PrivateGroup(group,
|
||||
getRandomString(5), getAuthor(), getRandomBytes(32));
|
||||
private final BdfDictionary meta = BdfDictionary.of(new BdfEntry("m", "e"));
|
||||
private final Message message = getMessage(contactGroup.getId());
|
||||
private final BdfList body = BdfList.of("body");
|
||||
@@ -159,9 +163,9 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
||||
will(returnValue(false));
|
||||
oneOf(db).addGroup(txn, localGroup);
|
||||
oneOf(db).getContacts(txn);
|
||||
will(returnValue(Collections.singletonList(contact)));
|
||||
will(returnValue(singletonList(contact)));
|
||||
}});
|
||||
expectAddingContact(contact);
|
||||
expectAddingContact(contact, emptyList());
|
||||
groupInvitationManager.onDatabaseOpened(txn);
|
||||
}
|
||||
|
||||
@@ -177,7 +181,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
||||
groupInvitationManager.onDatabaseOpened(txn);
|
||||
}
|
||||
|
||||
private void expectAddingContact(Contact c) throws Exception {
|
||||
private void expectAddingContact(Contact c, Collection<Group> groups)
|
||||
throws Exception {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||
MAJOR_VERSION, c);
|
||||
@@ -192,15 +197,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
||||
.setContactId(txn, contactGroup.getId(), contactId);
|
||||
oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||
PrivateGroupManager.MAJOR_VERSION);
|
||||
will(returnValue(Collections.singletonList(privateGroup)));
|
||||
oneOf(privateGroupManager).isMember(txn, privateGroup.getId(),
|
||||
c.getAuthor());
|
||||
will(returnValue(true));
|
||||
oneOf(privateGroupManager)
|
||||
.isOurPrivateGroup(txn, privateGroup.getId());
|
||||
will(returnValue(false));
|
||||
will(returnValue(groups));
|
||||
}});
|
||||
expectAddingMember(privateGroup.getId(), c);
|
||||
}
|
||||
|
||||
private void expectAddingMember(GroupId g, Contact c) throws Exception {
|
||||
@@ -254,13 +252,99 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
||||
|
||||
@Test
|
||||
public void testAddingContact() throws Exception {
|
||||
expectAddingContact(contact);
|
||||
expectAddingContact(contact, singletonList(group));
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(privateGroupManager)
|
||||
.isMember(txn, privateGroup.getId(), contact.getAuthor());
|
||||
will(returnValue(true));
|
||||
oneOf(privateGroupManager)
|
||||
.getPrivateGroup(txn, privateGroup.getId());
|
||||
will(returnValue(privateGroup));
|
||||
oneOf(privateGroupManager).isOurPrivateGroup(txn, privateGroup);
|
||||
will(returnValue(false));
|
||||
}});
|
||||
// creates PEER session
|
||||
expectAddingMember(privateGroup.getId(), contact);
|
||||
|
||||
groupInvitationManager.addingContact(txn, contact);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemovingContact() throws Exception {
|
||||
public void testAddingContactWhoCreatedGroup() throws Exception {
|
||||
PrivateGroup privateGroup = new PrivateGroup(group,
|
||||
getRandomString(5), contact.getAuthor(), getRandomBytes(32));
|
||||
|
||||
expectAddingContact(contact, singletonList(group));
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(privateGroupManager)
|
||||
.isMember(txn, privateGroup.getId(), contact.getAuthor());
|
||||
will(returnValue(true));
|
||||
oneOf(privateGroupManager)
|
||||
.getPrivateGroup(txn, privateGroup.getId());
|
||||
will(returnValue(privateGroup));
|
||||
oneOf(privateGroupManager).isOurPrivateGroup(txn, privateGroup);
|
||||
will(returnValue(false));
|
||||
}});
|
||||
expectCreateStorageId();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(sessionEncoder)
|
||||
.encodeSession(with(any(InviteeSession.class)));
|
||||
will(returnValue(meta));
|
||||
oneOf(clientHelper)
|
||||
.mergeMessageMetadata(txn, storageMessage.getId(), meta);
|
||||
}});
|
||||
|
||||
groupInvitationManager.addingContact(txn, contact);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemovingContactWithoutCommonGroups() throws Exception {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||
PrivateGroupManager.MAJOR_VERSION);
|
||||
will(returnValue(emptyList()));
|
||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||
MAJOR_VERSION, contact);
|
||||
will(returnValue(contactGroup));
|
||||
oneOf(db).removeGroup(txn, contactGroup);
|
||||
}});
|
||||
groupInvitationManager.removingContact(txn, contact);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemovingContactWithCommonGroups() throws Exception {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||
PrivateGroupManager.MAJOR_VERSION);
|
||||
will(returnValue(singletonList(group)));
|
||||
oneOf(privateGroupManager).isMember(txn, group.getId(), author);
|
||||
will(returnValue(true));
|
||||
oneOf(privateGroupManager).getPrivateGroup(txn, group.getId());
|
||||
will(returnValue(privateGroup));
|
||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||
MAJOR_VERSION, contact);
|
||||
will(returnValue(contactGroup));
|
||||
oneOf(db).removeGroup(txn, contactGroup);
|
||||
}});
|
||||
groupInvitationManager.removingContact(txn, contact);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemovingContactWhoIsCreatorOfCommonGroup()
|
||||
throws Exception {
|
||||
PrivateGroup privateGroup = new PrivateGroup(group,
|
||||
getRandomString(5), contact.getAuthor(), getRandomBytes(32));
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID,
|
||||
PrivateGroupManager.MAJOR_VERSION);
|
||||
will(returnValue(singletonList(group)));
|
||||
oneOf(privateGroupManager).isMember(txn, group.getId(), author);
|
||||
will(returnValue(true));
|
||||
oneOf(privateGroupManager).getPrivateGroup(txn, group.getId());
|
||||
will(returnValue(privateGroup));
|
||||
oneOf(privateGroupManager).markGroupDissolved(txn, group.getId());
|
||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||
MAJOR_VERSION, contact);
|
||||
will(returnValue(contactGroup));
|
||||
@@ -350,8 +434,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
||||
BdfDictionary bdfSession) throws Exception {
|
||||
expectParseMessageMetadata();
|
||||
expectGetSession(oneResult, sessionId, contactGroup.getId());
|
||||
Session<?> session =
|
||||
expectHandleMessage(role, messageMetadata, bdfSession, type);
|
||||
Session<?> session = expectHandleMessage(role, messageMetadata,
|
||||
bdfSession, type);
|
||||
expectStoreSession(session, storageMessage.getId());
|
||||
}
|
||||
|
||||
@@ -564,7 +648,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
||||
|
||||
@Test
|
||||
public void testAcceptInvitationWithGroupId() throws Exception {
|
||||
PrivateGroup pg = new PrivateGroup(privateGroup,
|
||||
PrivateGroup pg = new PrivateGroup(group,
|
||||
getRandomString(MAX_GROUP_NAME_LENGTH), author,
|
||||
getRandomBytes(GROUP_SALT_LENGTH));
|
||||
|
||||
@@ -574,7 +658,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
||||
|
||||
@Test
|
||||
public void testDeclineInvitationWithGroupId() throws Exception {
|
||||
PrivateGroup pg = new PrivateGroup(privateGroup,
|
||||
PrivateGroup pg = new PrivateGroup(group,
|
||||
getRandomString(MAX_GROUP_NAME_LENGTH), author,
|
||||
getRandomBytes(GROUP_SALT_LENGTH));
|
||||
|
||||
@@ -665,7 +749,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
||||
privateGroup.getId(), time1, "name", author,
|
||||
new byte[0], null, new byte[0], NO_AUTO_DELETE_TIMER);
|
||||
PrivateGroup pg =
|
||||
new PrivateGroup(privateGroup, invite.getGroupName(),
|
||||
new PrivateGroup(group, invite.getGroupName(),
|
||||
invite.getCreator(), invite.getSalt());
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
@@ -733,7 +817,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
||||
new InviteMessage(message2.getId(), contactGroup.getId(),
|
||||
privateGroup.getId(), time2, groupName, author, salt,
|
||||
null, getRandomBytes(5), NO_AUTO_DELETE_TIMER);
|
||||
PrivateGroup pg = new PrivateGroup(privateGroup, groupName,
|
||||
PrivateGroup pg = new PrivateGroup(group, groupName,
|
||||
author, salt);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
@@ -742,7 +826,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
oneOf(db).getContacts(txn);
|
||||
will(returnValue(Collections.singletonList(contact)));
|
||||
will(returnValue(singletonList(contact)));
|
||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||
MAJOR_VERSION, contact);
|
||||
will(returnValue(contactGroup));
|
||||
@@ -834,7 +918,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
|
||||
expectAddingMember(privateGroup.getId(), contact);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).getContactsByAuthorId(txn, author.getId());
|
||||
will(returnValue(Collections.singletonList(contact)));
|
||||
will(returnValue(singletonList(contact)));
|
||||
}});
|
||||
groupInvitationManager.addingMember(txn, privateGroup.getId(), author);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user