mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Add support for revealing contacts to the PrivateGroupManager
This also adds two integration tests and improves some small details
This commit is contained in:
@@ -11,6 +11,7 @@ import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.crypto.KeyPair;
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.db.DatabaseComponent;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.Transaction;
|
||||
import org.briarproject.api.event.Event;
|
||||
@@ -20,6 +21,7 @@ import org.briarproject.api.identity.AuthorFactory;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.api.privategroup.GroupMember;
|
||||
import org.briarproject.api.privategroup.GroupMessage;
|
||||
import org.briarproject.api.privategroup.GroupMessageFactory;
|
||||
import org.briarproject.api.privategroup.GroupMessageHeader;
|
||||
@@ -59,6 +61,10 @@ import javax.inject.Inject;
|
||||
import static org.briarproject.TestPluginsModule.MAX_LATENCY;
|
||||
import static org.briarproject.TestUtils.getRandomBytes;
|
||||
import static org.briarproject.api.identity.Author.Status.VERIFIED;
|
||||
import static org.briarproject.api.privategroup.Visibility.INVISIBLE;
|
||||
import static org.briarproject.api.privategroup.Visibility.REVEALED_BY_CONTACT;
|
||||
import static org.briarproject.api.privategroup.Visibility.REVEALED_BY_YOU;
|
||||
import static org.briarproject.api.privategroup.Visibility.VISIBLE;
|
||||
import static org.briarproject.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID;
|
||||
import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
|
||||
import static org.briarproject.api.sync.ValidationManager.State.INVALID;
|
||||
@@ -69,13 +75,16 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
|
||||
private LifecycleManager lifecycleManager0, lifecycleManager1;
|
||||
private SyncSessionFactory sync0, sync1;
|
||||
private PrivateGroupManager groupManager0, groupManager1;
|
||||
private ContactManager contactManager0, contactManager1;
|
||||
private ContactId contactId0, contactId1;
|
||||
private IdentityManager identityManager0, identityManager1;
|
||||
private LocalAuthor author0, author1;
|
||||
private LifecycleManager lifecycleManager0, lifecycleManager1,
|
||||
lifecycleManager2;
|
||||
private SyncSessionFactory sync0, sync1, sync2;
|
||||
private PrivateGroupManager groupManager0, groupManager1, groupManager2;
|
||||
private ContactManager contactManager0, contactManager1, contactManager2;
|
||||
private ContactId contactId01, contactId02, contactId1, contactId2;
|
||||
private IdentityManager identityManager0, identityManager1,
|
||||
identityManager2;
|
||||
private LocalAuthor author0, author1, author2;
|
||||
private DatabaseComponent db0, db1, db2;
|
||||
private PrivateGroup privateGroup0;
|
||||
private GroupId groupId0;
|
||||
|
||||
@@ -101,13 +110,14 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
private final File testDir = TestUtils.getTestDirectory();
|
||||
private final SecretKey master = TestUtils.getSecretKey();
|
||||
private final int TIMEOUT = 15000;
|
||||
private final String AUTHOR0 = "Author 0";
|
||||
private final String AUTHOR1 = "Author 1";
|
||||
private final String AUTHOR2 = "Author 2";
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(PrivateGroupManagerTest.class.getName());
|
||||
|
||||
private PrivateGroupManagerTestComponent t0, t1;
|
||||
private PrivateGroupManagerTestComponent t0, t1, t2;
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
@@ -117,26 +127,36 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
PrivateGroupManagerTestComponent component =
|
||||
DaggerPrivateGroupManagerTestComponent.builder().build();
|
||||
component.inject(this);
|
||||
injectEagerSingletons(component);
|
||||
|
||||
assertTrue(testDir.mkdirs());
|
||||
File t0Dir = new File(testDir, AUTHOR1);
|
||||
File t0Dir = new File(testDir, AUTHOR0);
|
||||
t0 = DaggerPrivateGroupManagerTestComponent.builder()
|
||||
.testDatabaseModule(new TestDatabaseModule(t0Dir)).build();
|
||||
injectEagerSingletons(t0);
|
||||
File t1Dir = new File(testDir, AUTHOR2);
|
||||
File t1Dir = new File(testDir, AUTHOR1);
|
||||
t1 = DaggerPrivateGroupManagerTestComponent.builder()
|
||||
.testDatabaseModule(new TestDatabaseModule(t1Dir)).build();
|
||||
injectEagerSingletons(t1);
|
||||
File t2Dir = new File(testDir, AUTHOR2);
|
||||
t2 = DaggerPrivateGroupManagerTestComponent.builder()
|
||||
.testDatabaseModule(new TestDatabaseModule(t2Dir)).build();
|
||||
injectEagerSingletons(t2);
|
||||
|
||||
identityManager0 = t0.getIdentityManager();
|
||||
identityManager1 = t1.getIdentityManager();
|
||||
identityManager2 = t2.getIdentityManager();
|
||||
contactManager0 = t0.getContactManager();
|
||||
contactManager1 = t1.getContactManager();
|
||||
contactManager2 = t2.getContactManager();
|
||||
db0 = t0.getDatabaseComponent();
|
||||
db1 = t1.getDatabaseComponent();
|
||||
db2 = t2.getDatabaseComponent();
|
||||
groupManager0 = t0.getPrivateGroupManager();
|
||||
groupManager1 = t1.getPrivateGroupManager();
|
||||
groupManager2 = t2.getPrivateGroupManager();
|
||||
sync0 = t0.getSyncSessionFactory();
|
||||
sync1 = t1.getSyncSessionFactory();
|
||||
sync2 = t2.getSyncSessionFactory();
|
||||
|
||||
// initialize waiters fresh for each test
|
||||
validationWaiter = new Waiter();
|
||||
@@ -328,12 +348,10 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
groupManager0.getPreviousMsgId(groupId0));
|
||||
|
||||
// make group visible to 1
|
||||
Transaction txn0 = t0.getDatabaseComponent().startTransaction(false);
|
||||
t0.getDatabaseComponent()
|
||||
.setVisibleToContact(txn0, contactId1, privateGroup0.getId(),
|
||||
true);
|
||||
t0.getDatabaseComponent().commitTransaction(txn0);
|
||||
t0.getDatabaseComponent().endTransaction(txn0);
|
||||
Transaction txn0 = db0.startTransaction(false);
|
||||
db0.setVisibleToContact(txn0, contactId1, privateGroup0.getId(), true);
|
||||
db0.commitTransaction(txn0);
|
||||
db0.endTransaction(txn0);
|
||||
|
||||
// author1 joins privateGroup0 with wrong timestamp
|
||||
joinTime = clock.currentTimeMillis();
|
||||
@@ -353,12 +371,10 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
groupManager1.getPreviousMsgId(groupId0));
|
||||
|
||||
// make group visible to 0
|
||||
Transaction txn1 = t1.getDatabaseComponent().startTransaction(false);
|
||||
t1.getDatabaseComponent()
|
||||
.setVisibleToContact(txn1, contactId0, privateGroup0.getId(),
|
||||
true);
|
||||
t1.getDatabaseComponent().commitTransaction(txn1);
|
||||
t1.getDatabaseComponent().endTransaction(txn1);
|
||||
Transaction txn1 = db1.startTransaction(false);
|
||||
db1.setVisibleToContact(txn1, contactId01, privateGroup0.getId(), true);
|
||||
db1.commitTransaction(txn1);
|
||||
db1.endTransaction(txn1);
|
||||
|
||||
// sync join messages
|
||||
sync0To1();
|
||||
@@ -399,12 +415,10 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
groupManager0.getPreviousMsgId(groupId0));
|
||||
|
||||
// make group visible to 1
|
||||
Transaction txn0 = t0.getDatabaseComponent().startTransaction(false);
|
||||
t0.getDatabaseComponent()
|
||||
.setVisibleToContact(txn0, contactId1, privateGroup0.getId(),
|
||||
true);
|
||||
t0.getDatabaseComponent().commitTransaction(txn0);
|
||||
t0.getDatabaseComponent().endTransaction(txn0);
|
||||
Transaction txn0 = db0.startTransaction(false);
|
||||
db0.setVisibleToContact(txn0, contactId1, privateGroup0.getId(), true);
|
||||
db0.commitTransaction(txn0);
|
||||
db0.endTransaction(txn0);
|
||||
|
||||
// author1 joins privateGroup0 with wrong signature in join message
|
||||
joinTime = clock.currentTimeMillis();
|
||||
@@ -424,12 +438,10 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
groupManager1.getPreviousMsgId(groupId0));
|
||||
|
||||
// make group visible to 0
|
||||
Transaction txn1 = t1.getDatabaseComponent().startTransaction(false);
|
||||
t1.getDatabaseComponent()
|
||||
.setVisibleToContact(txn1, contactId0, privateGroup0.getId(),
|
||||
true);
|
||||
t1.getDatabaseComponent().commitTransaction(txn1);
|
||||
t1.getDatabaseComponent().endTransaction(txn1);
|
||||
Transaction txn1 = db1.startTransaction(false);
|
||||
db1.setVisibleToContact(txn1, contactId01, privateGroup0.getId(), true);
|
||||
db1.commitTransaction(txn1);
|
||||
db1.endTransaction(txn1);
|
||||
|
||||
// sync join messages
|
||||
sync0To1();
|
||||
@@ -445,6 +457,119 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
assertEquals(1, groupManager0.getHeaders(groupId0).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMembers() throws Exception {
|
||||
defaultInit();
|
||||
|
||||
Collection<GroupMember> members0 = groupManager0.getMembers(groupId0);
|
||||
assertEquals(2, members0.size());
|
||||
for (GroupMember m : members0) {
|
||||
if (m.getAuthor().equals(author0)) {
|
||||
assertEquals(VISIBLE, m.getVisibility());
|
||||
} else {
|
||||
assertEquals(author1, m.getAuthor());
|
||||
assertEquals(VISIBLE, m.getVisibility());
|
||||
}
|
||||
}
|
||||
|
||||
Collection<GroupMember> members1 = groupManager1.getMembers(groupId0);
|
||||
assertEquals(2, members1.size());
|
||||
for (GroupMember m : members0) {
|
||||
if (m.getAuthor().equals(author1)) {
|
||||
assertEquals(VISIBLE, m.getVisibility());
|
||||
} else {
|
||||
assertEquals(author0, m.getAuthor());
|
||||
assertEquals(VISIBLE, m.getVisibility());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRevealingRelationships() throws Exception {
|
||||
defaultInit();
|
||||
|
||||
// make group visible to 2
|
||||
Transaction txn0 = db0.startTransaction(false);
|
||||
db0.setVisibleToContact(txn0, contactId2, privateGroup0.getId(), true);
|
||||
db0.commitTransaction(txn0);
|
||||
db0.endTransaction(txn0);
|
||||
|
||||
// author2 joins privateGroup0
|
||||
long joinTime = clock.currentTimeMillis();
|
||||
long inviteTime = joinTime - 1;
|
||||
Group invitationGroup = contactGroupFactory
|
||||
.createContactGroup(CLIENT_ID, author0.getId(),
|
||||
author2.getId());
|
||||
BdfList toSign = BdfList.of(0, inviteTime, invitationGroup.getId(),
|
||||
privateGroup0.getId());
|
||||
byte[] creatorSignature =
|
||||
clientHelper.sign(toSign, author0.getPrivateKey());
|
||||
GroupMessage joinMsg2 = groupMessageFactory
|
||||
.createJoinMessage(privateGroup0.getId(), joinTime, author2,
|
||||
inviteTime, creatorSignature);
|
||||
Transaction txn2 = db2.startTransaction(false);
|
||||
groupManager2.addPrivateGroup(txn2, privateGroup0, joinMsg2);
|
||||
|
||||
// make group visible to 0
|
||||
db2.setVisibleToContact(txn2, contactId01, privateGroup0.getId(), true);
|
||||
db2.commitTransaction(txn2);
|
||||
db2.endTransaction(txn2);
|
||||
|
||||
// sync join messages
|
||||
deliverMessage(sync2, contactId2, sync0, contactId02, "2 to 0");
|
||||
deliveryWaiter.await(TIMEOUT, 1);
|
||||
deliverMessage(sync0, contactId02, sync2, contactId2, "0 to 2");
|
||||
deliveryWaiter.await(TIMEOUT, 2);
|
||||
sync0To1();
|
||||
deliveryWaiter.await(TIMEOUT, 1);
|
||||
|
||||
// check that everybody sees everybody else as joined
|
||||
Collection<GroupMember> members0 = groupManager0.getMembers(groupId0);
|
||||
assertEquals(3, members0.size());
|
||||
Collection<GroupMember> members1 = groupManager1.getMembers(groupId0);
|
||||
assertEquals(3, members1.size());
|
||||
Collection<GroupMember> members2 = groupManager2.getMembers(groupId0);
|
||||
assertEquals(3, members2.size());
|
||||
|
||||
// assert that contact relationship is not revealed initially
|
||||
for (GroupMember m : members1) {
|
||||
if (m.getAuthor().equals(author2)) {
|
||||
assertEquals(INVISIBLE, m.getVisibility());
|
||||
}
|
||||
}
|
||||
for (GroupMember m : members2) {
|
||||
if (m.getAuthor().equals(author1)) {
|
||||
assertEquals(INVISIBLE, m.getVisibility());
|
||||
}
|
||||
}
|
||||
|
||||
// reveal contact relationship
|
||||
Transaction txn1 = db1.startTransaction(false);
|
||||
groupManager1
|
||||
.relationshipRevealed(txn1, groupId0, author2.getId(), false);
|
||||
db1.commitTransaction(txn1);
|
||||
db1.endTransaction(txn1);
|
||||
txn2 = db2.startTransaction(false);
|
||||
groupManager2
|
||||
.relationshipRevealed(txn2, groupId0, author1.getId(), true);
|
||||
db2.commitTransaction(txn2);
|
||||
db2.endTransaction(txn2);
|
||||
|
||||
// assert that contact relationship is now revealed properly
|
||||
members1 = groupManager1.getMembers(groupId0);
|
||||
for (GroupMember m : members1) {
|
||||
if (m.getAuthor().equals(author2)) {
|
||||
assertEquals(REVEALED_BY_YOU, m.getVisibility());
|
||||
}
|
||||
}
|
||||
members2 = groupManager2.getMembers(groupId0);
|
||||
for (GroupMember m : members2) {
|
||||
if (m.getAuthor().equals(author1)) {
|
||||
assertEquals(REVEALED_BY_CONTACT, m.getVisibility());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
stopLifecycles();
|
||||
@@ -483,7 +608,7 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
byte[] publicKey0 = keyPair0.getPublic().getEncoded();
|
||||
byte[] privateKey0 = keyPair0.getPrivate().getEncoded();
|
||||
author0 = authorFactory
|
||||
.createLocalAuthor(AUTHOR1, publicKey0, privateKey0);
|
||||
.createLocalAuthor(AUTHOR0, publicKey0, privateKey0);
|
||||
identityManager0.registerLocalAuthor(author0);
|
||||
privateGroup0 =
|
||||
privateGroupFactory.createPrivateGroup("Testgroup", author0);
|
||||
@@ -493,21 +618,34 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
byte[] publicKey1 = keyPair1.getPublic().getEncoded();
|
||||
byte[] privateKey1 = keyPair1.getPrivate().getEncoded();
|
||||
author1 = authorFactory
|
||||
.createLocalAuthor(AUTHOR2, publicKey1, privateKey1);
|
||||
.createLocalAuthor(AUTHOR1, publicKey1, privateKey1);
|
||||
identityManager1.registerLocalAuthor(author1);
|
||||
|
||||
KeyPair keyPair2 = crypto.generateSignatureKeyPair();
|
||||
byte[] publicKey2 = keyPair2.getPublic().getEncoded();
|
||||
byte[] privateKey2 = keyPair2.getPrivate().getEncoded();
|
||||
author2 = authorFactory
|
||||
.createLocalAuthor(AUTHOR2, publicKey2, privateKey2);
|
||||
identityManager2.registerLocalAuthor(author2);
|
||||
}
|
||||
|
||||
private void addDefaultContacts() throws DbException {
|
||||
// sharer adds invitee as contact
|
||||
contactId1 = contactManager0.addContact(author1,
|
||||
author0.getId(), master, clock.currentTimeMillis(), true,
|
||||
true, true
|
||||
);
|
||||
// invitee adds sharer back
|
||||
contactId0 = contactManager1.addContact(author0,
|
||||
author1.getId(), master, clock.currentTimeMillis(), true,
|
||||
true, true
|
||||
);
|
||||
// creator adds invitee as contact
|
||||
contactId1 = contactManager0
|
||||
.addContact(author1, author0.getId(), master,
|
||||
clock.currentTimeMillis(), true, true, true);
|
||||
// invitee adds creator back
|
||||
contactId01 = contactManager1
|
||||
.addContact(author0, author1.getId(), master,
|
||||
clock.currentTimeMillis(), true, true, true);
|
||||
// creator adds invitee as contact
|
||||
contactId2 = contactManager0
|
||||
.addContact(author2, author0.getId(), master,
|
||||
clock.currentTimeMillis(), true, true, true);
|
||||
// invitee adds creator back
|
||||
contactId02 = contactManager2
|
||||
.addContact(author0, author2.getId(), master,
|
||||
clock.currentTimeMillis(), true, true, true);
|
||||
}
|
||||
|
||||
private void listenToEvents() {
|
||||
@@ -515,6 +653,8 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
t0.getEventBus().addListener(listener0);
|
||||
Listener listener1 = new Listener();
|
||||
t1.getEventBus().addListener(listener1);
|
||||
Listener listener2 = new Listener();
|
||||
t2.getEventBus().addListener(listener2);
|
||||
}
|
||||
|
||||
private void addGroup() throws Exception {
|
||||
@@ -527,12 +667,10 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
groupManager0.getPreviousMsgId(groupId0));
|
||||
|
||||
// make group visible to 1
|
||||
Transaction txn0 = t0.getDatabaseComponent().startTransaction(false);
|
||||
t0.getDatabaseComponent()
|
||||
.setVisibleToContact(txn0, contactId1, privateGroup0.getId(),
|
||||
true);
|
||||
t0.getDatabaseComponent().commitTransaction(txn0);
|
||||
t0.getDatabaseComponent().endTransaction(txn0);
|
||||
Transaction txn0 = db0.startTransaction(false);
|
||||
db0.setVisibleToContact(txn0, contactId1, privateGroup0.getId(), true);
|
||||
db0.commitTransaction(txn0);
|
||||
db0.endTransaction(txn0);
|
||||
|
||||
// author1 joins privateGroup0
|
||||
joinTime = clock.currentTimeMillis();
|
||||
@@ -547,17 +685,15 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
GroupMessage joinMsg1 = groupMessageFactory
|
||||
.createJoinMessage(privateGroup0.getId(), joinTime, author1,
|
||||
inviteTime, creatorSignature);
|
||||
groupManager1.addPrivateGroup(privateGroup0, joinMsg1);
|
||||
assertEquals(joinMsg1.getMessage().getId(),
|
||||
groupManager1.getPreviousMsgId(groupId0));
|
||||
Transaction txn1 = db1.startTransaction(false);
|
||||
groupManager1.addPrivateGroup(txn1, privateGroup0, joinMsg1);
|
||||
|
||||
// make group visible to 0
|
||||
Transaction txn1 = t1.getDatabaseComponent().startTransaction(false);
|
||||
t1.getDatabaseComponent()
|
||||
.setVisibleToContact(txn1, contactId0, privateGroup0.getId(),
|
||||
true);
|
||||
t1.getDatabaseComponent().commitTransaction(txn1);
|
||||
t1.getDatabaseComponent().endTransaction(txn1);
|
||||
db1.setVisibleToContact(txn1, contactId01, privateGroup0.getId(), true);
|
||||
db1.commitTransaction(txn1);
|
||||
db1.endTransaction(txn1);
|
||||
assertEquals(joinMsg1.getMessage().getId(),
|
||||
groupManager1.getPreviousMsgId(groupId0));
|
||||
|
||||
// sync join messages
|
||||
sync0To1();
|
||||
@@ -567,11 +703,11 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
}
|
||||
|
||||
private void sync0To1() throws IOException, TimeoutException {
|
||||
deliverMessage(sync0, contactId0, sync1, contactId1, "0 to 1");
|
||||
deliverMessage(sync0, contactId01, sync1, contactId1, "0 to 1");
|
||||
}
|
||||
|
||||
private void sync1To0() throws IOException, TimeoutException {
|
||||
deliverMessage(sync1, contactId1, sync0, contactId0, "1 to 0");
|
||||
deliverMessage(sync1, contactId1, sync0, contactId01, "1 to 0");
|
||||
}
|
||||
|
||||
private void deliverMessage(SyncSessionFactory fromSync, ContactId fromId,
|
||||
@@ -600,18 +736,23 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
|
||||
// Start the lifecycle manager and wait for it to finish
|
||||
lifecycleManager0 = t0.getLifecycleManager();
|
||||
lifecycleManager1 = t1.getLifecycleManager();
|
||||
lifecycleManager0.startServices(AUTHOR1);
|
||||
lifecycleManager1.startServices(AUTHOR2);
|
||||
lifecycleManager2 = t2.getLifecycleManager();
|
||||
lifecycleManager0.startServices(AUTHOR0);
|
||||
lifecycleManager1.startServices(AUTHOR1);
|
||||
lifecycleManager2.startServices(AUTHOR2);
|
||||
lifecycleManager0.waitForStartup();
|
||||
lifecycleManager1.waitForStartup();
|
||||
lifecycleManager2.waitForStartup();
|
||||
}
|
||||
|
||||
private void stopLifecycles() throws InterruptedException {
|
||||
// Clean up
|
||||
lifecycleManager0.stopServices();
|
||||
lifecycleManager1.stopServices();
|
||||
lifecycleManager2.stopServices();
|
||||
lifecycleManager0.waitForShutdown();
|
||||
lifecycleManager1.waitForShutdown();
|
||||
lifecycleManager2.waitForShutdown();
|
||||
}
|
||||
|
||||
private void injectEagerSingletons(
|
||||
|
||||
@@ -105,7 +105,7 @@ public class GroupActivity extends
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setSubtitle(getString(R.string.groups_created_by,
|
||||
group.getAuthor().getName()));
|
||||
group.getCreator().getName()));
|
||||
}
|
||||
controller.isCreator(group,
|
||||
new UiResultExceptionHandler<Boolean, DbException>(this) {
|
||||
|
||||
@@ -196,7 +196,7 @@ public class GroupControllerImpl extends
|
||||
try {
|
||||
LocalAuthor author = identityManager.getLocalAuthor();
|
||||
boolean isCreator =
|
||||
author.getId().equals(group.getAuthor().getId());
|
||||
author.getId().equals(group.getCreator().getId());
|
||||
handler.onResult(isCreator);
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
|
||||
@@ -43,7 +43,7 @@ class GroupItem {
|
||||
}
|
||||
|
||||
Author getCreator() {
|
||||
return privateGroup.getAuthor();
|
||||
return privateGroup.getCreator();
|
||||
}
|
||||
|
||||
String getName() {
|
||||
|
||||
@@ -7,6 +7,8 @@ import org.briarproject.api.privategroup.GroupMember;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import static org.briarproject.api.privategroup.Visibility.INVISIBLE;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
class MemberListItem {
|
||||
@@ -17,7 +19,7 @@ class MemberListItem {
|
||||
|
||||
public MemberListItem(GroupMember groupMember) {
|
||||
this.member = groupMember.getAuthor();
|
||||
this.sharing = groupMember.isShared();
|
||||
this.sharing = groupMember.getVisibility() != INVISIBLE; // TODO #732
|
||||
this.status = groupMember.getStatus();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ public class GroupMember {
|
||||
|
||||
private final Author author;
|
||||
private final Status status;
|
||||
private final boolean shared;
|
||||
private final Visibility visibility;
|
||||
|
||||
public GroupMember(Author author, Status status, boolean shared) {
|
||||
public GroupMember(Author author, Status status, Visibility visibility) {
|
||||
this.author = author;
|
||||
this.status = status;
|
||||
this.shared = shared;
|
||||
this.visibility = visibility;
|
||||
}
|
||||
|
||||
public Author getAuthor() {
|
||||
@@ -28,8 +28,8 @@ public class GroupMember {
|
||||
return status;
|
||||
}
|
||||
|
||||
public boolean isShared() {
|
||||
return shared;
|
||||
public Visibility getVisibility() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,20 +12,22 @@ import javax.annotation.concurrent.Immutable;
|
||||
@NotNullByDefault
|
||||
public class PrivateGroup extends NamedGroup implements Shareable {
|
||||
|
||||
private final Author author;
|
||||
private final Author creator;
|
||||
|
||||
public PrivateGroup(Group group, String name, Author author, byte[] salt) {
|
||||
public PrivateGroup(Group group, String name, Author creator, byte[] salt) {
|
||||
super(group, name, salt);
|
||||
this.author = author;
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
public Author getAuthor() {
|
||||
return author;
|
||||
public Author getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof PrivateGroup && super.equals(o);
|
||||
return o instanceof PrivateGroup &&
|
||||
creator.equals(((PrivateGroup) o).getCreator()) &&
|
||||
super.equals(o);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package org.briarproject.api.privategroup;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.clients.MessageTracker;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.Transaction;
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.identity.AuthorId;
|
||||
import org.briarproject.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.api.sync.ClientId;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
@@ -20,16 +22,16 @@ public interface PrivateGroupManager extends MessageTracker {
|
||||
ClientId CLIENT_ID = new ClientId("org.briarproject.briar.privategroup");
|
||||
|
||||
/**
|
||||
* Adds a new private group and joins it.
|
||||
* Adds a new private group and joins it as the creator.
|
||||
*
|
||||
* @param group The private group to add
|
||||
* @param joinMsg The new member's join message
|
||||
* @param joinMsg The creators's join message
|
||||
*/
|
||||
void addPrivateGroup(PrivateGroup group, GroupMessage joinMsg)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Adds a new private group and joins it.
|
||||
* Adds a new private group and joins it as a member.
|
||||
*
|
||||
* @param group The private group to add
|
||||
* @param joinMsg The new member's join message
|
||||
@@ -103,6 +105,17 @@ public interface PrivateGroupManager extends MessageTracker {
|
||||
*/
|
||||
boolean isMember(Transaction txn, GroupId g, Author a) throws DbException;
|
||||
|
||||
/**
|
||||
* This method needs to be called when a contact relationship
|
||||
* has been revealed between you and the Author with AuthorId a
|
||||
* in the Group identified by the GroupId g.
|
||||
*
|
||||
* @param byContact true if the remote contact has revealed
|
||||
* the relationship first. Otherwise false.
|
||||
*/
|
||||
void relationshipRevealed(Transaction txn, GroupId g, AuthorId a,
|
||||
boolean byContact) throws FormatException, DbException;
|
||||
|
||||
/**
|
||||
* Registers a hook to be called when members are added
|
||||
* or groups are removed.
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.briarproject.api.privategroup;
|
||||
|
||||
public enum Visibility {
|
||||
|
||||
INVISIBLE(0),
|
||||
VISIBLE(1),
|
||||
REVEALED_BY_YOU(2),
|
||||
REVEALED_BY_CONTACT(3);
|
||||
|
||||
int value;
|
||||
|
||||
Visibility(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static Visibility valueOf(int value) {
|
||||
for (Visibility v : values()) if (v.value == value) return v;
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
public int getInt() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,13 +9,15 @@ interface Constants {
|
||||
String KEY_TIMESTAMP = "timestamp";
|
||||
String KEY_READ = MSG_KEY_READ;
|
||||
String KEY_PARENT_MSG_ID = "parentMsgId";
|
||||
String KEY_NEW_MEMBER_MSG_ID = "newMemberMsgId";
|
||||
String KEY_PREVIOUS_MSG_ID = "previousMsgId";
|
||||
String KEY_MEMBER_ID = "memberId";
|
||||
String KEY_MEMBER_NAME = "memberName";
|
||||
String KEY_MEMBER_PUBLIC_KEY = "memberPublicKey";
|
||||
|
||||
String KEY_MEMBERS = "members";
|
||||
String KEY_DISSOLVED = "dissolved";
|
||||
String GROUP_KEY_MEMBERS = "members";
|
||||
String GROUP_KEY_OUR_GROUP = "ourGroup";
|
||||
String GROUP_KEY_CREATOR_ID = "creatorId";
|
||||
String GROUP_KEY_DISSOLVED = "dissolved";
|
||||
String GROUP_KEY_VISIBILITY = "visibility";
|
||||
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ class GroupMessageValidator extends BdfMessageValidator {
|
||||
PrivateGroup pg = privateGroupFactory.parsePrivateGroup(g);
|
||||
|
||||
// invite is null if the member is the creator of the private group
|
||||
Author creator = pg.getAuthor();
|
||||
Author creator = pg.getCreator();
|
||||
BdfList invite = body.getOptionalList(3);
|
||||
if (invite == null) {
|
||||
if (!member.equals(creator))
|
||||
|
||||
@@ -2,8 +2,7 @@ package org.briarproject.privategroup;
|
||||
|
||||
import org.briarproject.api.FormatException;
|
||||
import org.briarproject.api.clients.ClientHelper;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.clients.ProtocolStateException;
|
||||
import org.briarproject.api.data.BdfDictionary;
|
||||
import org.briarproject.api.data.BdfEntry;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
@@ -27,6 +26,7 @@ import org.briarproject.api.privategroup.MessageType;
|
||||
import org.briarproject.api.privategroup.PrivateGroup;
|
||||
import org.briarproject.api.privategroup.PrivateGroupFactory;
|
||||
import org.briarproject.api.privategroup.PrivateGroupManager;
|
||||
import org.briarproject.api.privategroup.Visibility;
|
||||
import org.briarproject.api.sync.Group;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.Message;
|
||||
@@ -48,12 +48,17 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.api.identity.Author.Status.OURSELVES;
|
||||
import static org.briarproject.api.identity.Author.Status.UNVERIFIED;
|
||||
import static org.briarproject.api.identity.Author.Status.VERIFIED;
|
||||
import static org.briarproject.api.privategroup.MessageType.JOIN;
|
||||
import static org.briarproject.api.privategroup.MessageType.POST;
|
||||
import static org.briarproject.privategroup.Constants.KEY_DISSOLVED;
|
||||
import static org.briarproject.privategroup.Constants.KEY_MEMBERS;
|
||||
import static org.briarproject.api.privategroup.Visibility.INVISIBLE;
|
||||
import static org.briarproject.api.privategroup.Visibility.REVEALED_BY_CONTACT;
|
||||
import static org.briarproject.api.privategroup.Visibility.REVEALED_BY_YOU;
|
||||
import static org.briarproject.api.privategroup.Visibility.VISIBLE;
|
||||
import static org.briarproject.privategroup.Constants.GROUP_KEY_CREATOR_ID;
|
||||
import static org.briarproject.privategroup.Constants.GROUP_KEY_DISSOLVED;
|
||||
import static org.briarproject.privategroup.Constants.GROUP_KEY_MEMBERS;
|
||||
import static org.briarproject.privategroup.Constants.GROUP_KEY_OUR_GROUP;
|
||||
import static org.briarproject.privategroup.Constants.GROUP_KEY_VISIBILITY;
|
||||
import static org.briarproject.privategroup.Constants.KEY_MEMBER_ID;
|
||||
import static org.briarproject.privategroup.Constants.KEY_MEMBER_NAME;
|
||||
import static org.briarproject.privategroup.Constants.KEY_MEMBER_PUBLIC_KEY;
|
||||
@@ -88,7 +93,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
throws DbException {
|
||||
Transaction txn = db.startTransaction(false);
|
||||
try {
|
||||
addPrivateGroup(txn, group, joinMsg);
|
||||
addPrivateGroup(txn, group, joinMsg, true);
|
||||
db.commitTransaction(txn);
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
@@ -98,11 +103,19 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
@Override
|
||||
public void addPrivateGroup(Transaction txn, PrivateGroup group,
|
||||
GroupMessage joinMsg) throws DbException {
|
||||
addPrivateGroup(txn, group, joinMsg, false);
|
||||
}
|
||||
|
||||
private void addPrivateGroup(Transaction txn, PrivateGroup group,
|
||||
GroupMessage joinMsg, boolean creator) throws DbException {
|
||||
try {
|
||||
db.addGroup(txn, group.getGroup());
|
||||
AuthorId creatorId = joinMsg.getMember().getId();
|
||||
BdfDictionary meta = BdfDictionary.of(
|
||||
new BdfEntry(KEY_MEMBERS, new BdfList()),
|
||||
new BdfEntry(KEY_DISSOLVED, false)
|
||||
new BdfEntry(GROUP_KEY_MEMBERS, new BdfList()),
|
||||
new BdfEntry(GROUP_KEY_CREATOR_ID, creatorId),
|
||||
new BdfEntry(GROUP_KEY_OUR_GROUP, creator),
|
||||
new BdfEntry(GROUP_KEY_DISSOLVED, false)
|
||||
);
|
||||
clientHelper.mergeGroupMetadata(txn, group.getId(), meta);
|
||||
joinPrivateGroup(txn, joinMsg);
|
||||
@@ -118,7 +131,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
addMessageMetadata(meta, m, true);
|
||||
clientHelper.addLocalMessage(txn, m.getMessage(), meta, true);
|
||||
trackOutgoingMessage(txn, m.getMessage());
|
||||
addMember(txn, m.getMessage().getGroupId(), m.getMember());
|
||||
addMember(txn, m.getMessage().getGroupId(), m.getMember(), VISIBLE);
|
||||
setPreviousMsgId(txn, m.getMessage().getGroupId(),
|
||||
m.getMessage().getId());
|
||||
}
|
||||
@@ -171,7 +184,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
public void markGroupDissolved(Transaction txn, GroupId g)
|
||||
throws DbException {
|
||||
BdfDictionary meta = BdfDictionary.of(
|
||||
new BdfEntry(KEY_DISSOLVED, true)
|
||||
new BdfEntry(GROUP_KEY_DISSOLVED, true)
|
||||
);
|
||||
try {
|
||||
clientHelper.mergeGroupMetadata(txn, g, meta);
|
||||
@@ -283,7 +296,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
public boolean isDissolved(GroupId g) throws DbException {
|
||||
try {
|
||||
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(g);
|
||||
return meta.getBoolean(KEY_DISSOLVED);
|
||||
return meta.getBoolean(GROUP_KEY_DISSOLVED);
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
@@ -376,18 +389,11 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
Collection<GroupMember> members = new ArrayList<GroupMember>();
|
||||
Collection<Author> authors = getMembers(txn, g);
|
||||
for (Author a : authors) {
|
||||
Status status = identityManager.getAuthorStatus(txn, a.getId());
|
||||
boolean shared = false;
|
||||
if (status == VERIFIED || status == UNVERIFIED) {
|
||||
Collection<Contact> contacts =
|
||||
db.getContactsByAuthorId(txn, a.getId());
|
||||
if (contacts.size() != 1) throw new DbException();
|
||||
ContactId c = contacts.iterator().next().getId();
|
||||
shared = db.isVisibleToContact(txn, c, g);
|
||||
}
|
||||
members.add(new GroupMember(a, status, shared));
|
||||
Map<Author, Visibility> authors = getMembers(txn, g);
|
||||
for (Entry<Author, Visibility> m : authors.entrySet()) {
|
||||
Status status = identityManager
|
||||
.getAuthorStatus(txn, m.getKey().getId());
|
||||
members.add(new GroupMember(m.getKey(), status, m.getValue()));
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
return members;
|
||||
@@ -396,17 +402,19 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<Author> getMembers(Transaction txn, GroupId g)
|
||||
private Map<Author, Visibility> getMembers(Transaction txn, GroupId g)
|
||||
throws DbException {
|
||||
try {
|
||||
Collection<Author> members = new ArrayList<Author>();
|
||||
BdfDictionary meta =
|
||||
clientHelper.getGroupMetadataAsDictionary(txn, g);
|
||||
BdfList list = meta.getList(KEY_MEMBERS);
|
||||
BdfList list = meta.getList(GROUP_KEY_MEMBERS);
|
||||
Map<Author, Visibility> members =
|
||||
new HashMap<Author, Visibility>(list.size());
|
||||
for (Object o : list) {
|
||||
BdfDictionary d = (BdfDictionary) o;
|
||||
Author member = getAuthor(d);
|
||||
members.add(member);
|
||||
Visibility v = getVisibility(d);
|
||||
members.put(member, v);
|
||||
}
|
||||
return members;
|
||||
} catch (FormatException e) {
|
||||
@@ -417,12 +425,34 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
@Override
|
||||
public boolean isMember(Transaction txn, GroupId g, Author a)
|
||||
throws DbException {
|
||||
for (Author member : getMembers(txn, g)) {
|
||||
for (Author member : getMembers(txn, g).keySet()) {
|
||||
if (member.equals(a)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void relationshipRevealed(Transaction txn, GroupId g, AuthorId a,
|
||||
boolean byContact) throws FormatException, DbException {
|
||||
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn, g);
|
||||
BdfList members = meta.getList(GROUP_KEY_MEMBERS);
|
||||
boolean foundMember = false;
|
||||
for (Object o : members) {
|
||||
BdfDictionary d = (BdfDictionary) o;
|
||||
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();
|
||||
Visibility vNew =
|
||||
byContact ? REVEALED_BY_CONTACT : REVEALED_BY_YOU;
|
||||
d.put(GROUP_KEY_VISIBILITY, vNew.getInt());
|
||||
}
|
||||
}
|
||||
if (!foundMember) throw new ProtocolStateException();
|
||||
clientHelper.mergeGroupMetadata(txn, g, meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerPrivateGroupHook(PrivateGroupHook hook) {
|
||||
hooks.add(hook);
|
||||
@@ -432,47 +462,14 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
|
||||
BdfDictionary meta) throws DbException, FormatException {
|
||||
|
||||
long timestamp = meta.getLong(KEY_TIMESTAMP);
|
||||
MessageType type =
|
||||
MessageType.valueOf(meta.getLong(KEY_TYPE).intValue());
|
||||
switch (type) {
|
||||
case JOIN:
|
||||
addMember(txn, m.getGroupId(), getAuthor(meta));
|
||||
trackIncomingMessage(txn, m);
|
||||
attachGroupMessageAddedEvent(txn, m, meta, false);
|
||||
handleJoinMessage(txn, m, meta);
|
||||
return true;
|
||||
case POST:
|
||||
// timestamp must be greater than the timestamps of parent post
|
||||
byte[] parentIdBytes = meta.getOptionalRaw(KEY_PARENT_MSG_ID);
|
||||
if (parentIdBytes != null) {
|
||||
MessageId parentId = new MessageId(parentIdBytes);
|
||||
BdfDictionary parentMeta = clientHelper
|
||||
.getMessageMetadataAsDictionary(txn, parentId);
|
||||
if (timestamp <= parentMeta.getLong(KEY_TIMESTAMP))
|
||||
throw new FormatException();
|
||||
MessageType parentType = MessageType
|
||||
.valueOf(parentMeta.getLong(KEY_TYPE).intValue());
|
||||
if (parentType != POST)
|
||||
throw new FormatException();
|
||||
}
|
||||
// and the member's previous message
|
||||
byte[] previousMsgIdBytes = meta.getRaw(KEY_PREVIOUS_MSG_ID);
|
||||
MessageId previousMsgId = new MessageId(previousMsgIdBytes);
|
||||
BdfDictionary previousMeta = clientHelper
|
||||
.getMessageMetadataAsDictionary(txn, previousMsgId);
|
||||
if (timestamp <= previousMeta.getLong(KEY_TIMESTAMP))
|
||||
throw new FormatException();
|
||||
// previous message must be from same member
|
||||
if (!Arrays.equals(meta.getRaw(KEY_MEMBER_ID),
|
||||
previousMeta.getRaw(KEY_MEMBER_ID)))
|
||||
throw new FormatException();
|
||||
// previous message must be a POST or JOIN
|
||||
MessageType previousType = MessageType
|
||||
.valueOf(previousMeta.getLong(KEY_TYPE).intValue());
|
||||
if (previousType != JOIN && previousType != POST)
|
||||
throw new FormatException();
|
||||
trackIncomingMessage(txn, m);
|
||||
attachGroupMessageAddedEvent(txn, m, meta, false);
|
||||
handleGroupMessage(txn, m, meta);
|
||||
return true;
|
||||
default:
|
||||
// the validator should only let valid types pass
|
||||
@@ -480,6 +477,63 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
}
|
||||
}
|
||||
|
||||
private void handleJoinMessage(Transaction txn, Message m,
|
||||
BdfDictionary meta) throws FormatException, DbException {
|
||||
// find out if contact relationship is visible and then add new member
|
||||
Author member = getAuthor(meta);
|
||||
BdfDictionary groupMeta = clientHelper
|
||||
.getGroupMetadataAsDictionary(txn, m.getGroupId());
|
||||
boolean ourGroup = groupMeta.getBoolean(GROUP_KEY_OUR_GROUP);
|
||||
Visibility v = VISIBLE;
|
||||
if (!ourGroup) {
|
||||
AuthorId creatorId = new AuthorId(
|
||||
groupMeta.getRaw(GROUP_KEY_CREATOR_ID));
|
||||
if (!creatorId.equals(member.getId()))
|
||||
v = INVISIBLE;
|
||||
}
|
||||
addMember(txn, m.getGroupId(), member, v);
|
||||
// track message and broadcast event
|
||||
trackIncomingMessage(txn, m);
|
||||
attachGroupMessageAddedEvent(txn, m, meta, false);
|
||||
}
|
||||
|
||||
private void handleGroupMessage(Transaction txn, Message m,
|
||||
BdfDictionary meta) throws FormatException, DbException {
|
||||
// timestamp must be greater than the timestamps of parent post
|
||||
long timestamp = meta.getLong(KEY_TIMESTAMP);
|
||||
byte[] parentIdBytes = meta.getOptionalRaw(KEY_PARENT_MSG_ID);
|
||||
if (parentIdBytes != null) {
|
||||
MessageId parentId = new MessageId(parentIdBytes);
|
||||
BdfDictionary parentMeta = clientHelper
|
||||
.getMessageMetadataAsDictionary(txn, parentId);
|
||||
if (timestamp <= parentMeta.getLong(KEY_TIMESTAMP))
|
||||
throw new FormatException();
|
||||
MessageType parentType = MessageType
|
||||
.valueOf(parentMeta.getLong(KEY_TYPE).intValue());
|
||||
if (parentType != POST)
|
||||
throw new FormatException();
|
||||
}
|
||||
// and the member's previous message
|
||||
byte[] previousMsgIdBytes = meta.getRaw(KEY_PREVIOUS_MSG_ID);
|
||||
MessageId previousMsgId = new MessageId(previousMsgIdBytes);
|
||||
BdfDictionary previousMeta = clientHelper
|
||||
.getMessageMetadataAsDictionary(txn, previousMsgId);
|
||||
if (timestamp <= previousMeta.getLong(KEY_TIMESTAMP))
|
||||
throw new FormatException();
|
||||
// previous message must be from same member
|
||||
if (!Arrays.equals(meta.getRaw(KEY_MEMBER_ID),
|
||||
previousMeta.getRaw(KEY_MEMBER_ID)))
|
||||
throw new FormatException();
|
||||
// previous message must be a POST or JOIN
|
||||
MessageType previousType = MessageType
|
||||
.valueOf(previousMeta.getLong(KEY_TYPE).intValue());
|
||||
if (previousType != JOIN && previousType != POST)
|
||||
throw new FormatException();
|
||||
// track message and broadcast event
|
||||
trackIncomingMessage(txn, m);
|
||||
attachGroupMessageAddedEvent(txn, m, meta, false);
|
||||
}
|
||||
|
||||
private void attachGroupMessageAddedEvent(Transaction txn, Message m,
|
||||
BdfDictionary meta, boolean local)
|
||||
throws DbException, FormatException {
|
||||
@@ -489,15 +543,16 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
txn.attach(e);
|
||||
}
|
||||
|
||||
private void addMember(Transaction txn, GroupId g, Author a)
|
||||
private void addMember(Transaction txn, GroupId g, Author a, Visibility v)
|
||||
throws DbException, FormatException {
|
||||
|
||||
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn, g);
|
||||
BdfList members = meta.getList(KEY_MEMBERS);
|
||||
BdfList members = meta.getList(GROUP_KEY_MEMBERS);
|
||||
members.add(BdfDictionary.of(
|
||||
new BdfEntry(KEY_MEMBER_ID, a.getId()),
|
||||
new BdfEntry(KEY_MEMBER_NAME, a.getName()),
|
||||
new BdfEntry(KEY_MEMBER_PUBLIC_KEY, a.getPublicKey())
|
||||
new BdfEntry(KEY_MEMBER_PUBLIC_KEY, a.getPublicKey()),
|
||||
new BdfEntry(GROUP_KEY_VISIBILITY, v.getInt())
|
||||
));
|
||||
clientHelper.mergeGroupMetadata(txn, g, meta);
|
||||
for (PrivateGroupHook hook : hooks) {
|
||||
@@ -512,4 +567,10 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
|
||||
return new Author(authorId, name, publicKey);
|
||||
}
|
||||
|
||||
private Visibility getVisibility(BdfDictionary meta)
|
||||
throws FormatException {
|
||||
return Visibility
|
||||
.valueOf(meta.getLong(GROUP_KEY_VISIBILITY).intValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ abstract class AbstractProtocolEngine<S extends Session>
|
||||
}
|
||||
Message m = messageEncoder.encodeInviteMessage(
|
||||
session.getContactGroupId(), privateGroup.getId(),
|
||||
timestamp, privateGroup.getName(), privateGroup.getAuthor(),
|
||||
timestamp, privateGroup.getName(), privateGroup.getCreator(),
|
||||
privateGroup.getSalt(), message, signature);
|
||||
sendMessage(txn, m, INVITE, privateGroup.getId(), true);
|
||||
return m;
|
||||
|
||||
Reference in New Issue
Block a user