Only allow one private group (the inbox) to be shared with each contact.

This commit is contained in:
akwizgran
2013-12-19 22:12:49 +00:00
parent 0dc869228b
commit caec26e9cd
8 changed files with 68 additions and 61 deletions

View File

@@ -208,8 +208,8 @@ SelectContactsDialog.Listener {
long now = System.currentTimeMillis();
if(subscribe) {
if(!wasSubscribed) db.addGroup(group);
db.setVisibleToAll(group.getId(), all);
if(!all) db.setVisibility(group.getId(), visible);
db.setVisibleToAll(group, all);
if(!all) db.setVisibility(group, visible);
} else if(wasSubscribed) {
db.removeGroup(group);
}

View File

@@ -176,8 +176,8 @@ SelectContactsDialog.Listener {
Group g = groupFactory.createGroup(name, false);
long now = System.currentTimeMillis();
db.addGroup(g);
if(all) db.setVisibleToAll(g.getId(), true);
else db.setVisibility(g.getId(), visible);
if(all) db.setVisibleToAll(g, true);
else db.setVisibility(g, visible);
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Storing group took " + duration + " ms");

View File

@@ -348,16 +348,15 @@ public interface DatabaseComponent {
void setSeen(ContactId c, Collection<MessageId> seen) throws DbException;
/**
* Makes the given group visible to the given set of contacts and invisible
* Makes a public group visible to the given set of contacts and invisible
* to any other current or future contacts.
*/
void setVisibility(GroupId g, Collection<ContactId> visible)
void setVisibility(Group g, Collection<ContactId> visible)
throws DbException;
/**
* Makes the given group visible or invisible to future contacts by default.
* If <tt>visible</tt> is true, the group is also made visible to all
* current contacts.
* Makes a public group visible to all current and future contacts, or
* invisible to future contacts.
*/
void setVisibleToAll(GroupId g, boolean all) throws DbException;
void setVisibleToAll(Group g, boolean all) throws DbException;
}

View File

@@ -152,11 +152,11 @@ interface Database<T> {
throws DbException;
/**
* Makes the given group visible to the given contact.
* Makes a public group visible to the given contact.
* <p>
* Locking: subscription write.
*/
void addVisibility(T txn, ContactId c, GroupId g) throws DbException;
void addVisibility(T txn, ContactId c, Group g) throws DbException;
/**
* Returns true if the database contains the given contact.
@@ -616,11 +616,11 @@ interface Database<T> {
void removeTransport(T txn, TransportId t) throws DbException;
/**
* Makes the given group invisible to the given contact.
* Makes a public group invisible to the given contact.
* <p>
* Locking: subscription write.
*/
void removeVisibility(T txn, ContactId c, GroupId g) throws DbException;
void removeVisibility(T txn, ContactId c, Group g) throws DbException;
/**
* Sets the connection reordering window for the given endpoint in the
@@ -732,11 +732,11 @@ interface Database<T> {
long version) throws DbException;
/**
* Makes the given group visible or invisible to future contacts by default.
* Makes a public group visible or invisible to future contacts by default.
* <p>
* Locking: subscription write.
*/
void setVisibleToAll(T txn, GroupId g, boolean all) throws DbException;
void setVisibleToAll(T txn, Group g, boolean all) throws DbException;
/**
* Updates the expiry times of the given messages with respect to the given

View File

@@ -1871,8 +1871,9 @@ DatabaseCleaner.Callback {
}
}
public void setVisibility(GroupId g, Collection<ContactId> visible)
public void setVisibility(Group g, Collection<ContactId> visible)
throws DbException {
if(g.isPrivate()) throw new IllegalArgumentException();
Collection<ContactId> affected = new ArrayList<ContactId>();
contactLock.readLock().lock();
try {
@@ -1880,11 +1881,12 @@ DatabaseCleaner.Callback {
try {
T txn = db.startTransaction();
try {
if(!db.containsGroup(txn, g))
if(!db.containsGroup(txn, g.getId()))
throw new NoSuchSubscriptionException();
// Use HashSets for O(1) lookups, O(n) overall running time
HashSet<ContactId> now = new HashSet<ContactId>(visible);
Collection<ContactId> before = db.getVisibility(txn, g);
Collection<ContactId> before =
db.getVisibility(txn, g.getId());
before = new HashSet<ContactId>(before);
// Set the group's visibility for each current contact
for(ContactId c : db.getContactIds(txn)) {
@@ -1915,7 +1917,8 @@ DatabaseCleaner.Callback {
callListeners(new LocalSubscriptionsUpdatedEvent(affected));
}
public void setVisibleToAll(GroupId g, boolean all) throws DbException {
public void setVisibleToAll(Group g, boolean all) throws DbException {
if(g.isPrivate()) throw new IllegalArgumentException();
Collection<ContactId> affected = new ArrayList<ContactId>();
contactLock.readLock().lock();
try {
@@ -1923,13 +1926,14 @@ DatabaseCleaner.Callback {
try {
T txn = db.startTransaction();
try {
if(!db.containsGroup(txn, g))
if(!db.containsGroup(txn, g.getId()))
throw new NoSuchSubscriptionException();
// Make the group visible or invisible to future contacts
db.setVisibleToAll(txn, g, all);
if(all) {
// Make the group visible to all current contacts
Collection<ContactId> before = db.getVisibility(txn, g);
Collection<ContactId> before =
db.getVisibility(txn, g.getId());
before = new HashSet<ContactId>(before);
for(ContactId c : db.getContactIds(txn)) {
if(!before.contains(c)) {

View File

@@ -900,8 +900,9 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public void addVisibility(Connection txn, ContactId c, GroupId g)
public void addVisibility(Connection txn, ContactId c, Group g)
throws DbException {
if(g.isPrivate()) throw new IllegalArgumentException();
PreparedStatement ps = null;
try {
String sql = "INSERT INTO groupVisibilities"
@@ -909,7 +910,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " VALUES (?, ?, FALSE)";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setBytes(2, g.getBytes());
ps.setBytes(2, g.getId().getBytes());
int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException();
ps.close();
@@ -2633,15 +2634,16 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public void removeVisibility(Connection txn, ContactId c, GroupId g)
public void removeVisibility(Connection txn, ContactId c, Group g)
throws DbException {
if(g.isPrivate()) throw new IllegalArgumentException();
PreparedStatement ps = null;
try {
String sql = "DELETE FROM groupVisibilities"
+ " WHERE contactId = ? AND groupId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setBytes(2, g.getBytes());
ps.setBytes(2, g.getId().getBytes());
int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException();
ps.close();
@@ -3074,14 +3076,15 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public void setVisibleToAll(Connection txn, GroupId g, boolean all)
public void setVisibleToAll(Connection txn, Group g, boolean all)
throws DbException {
if(g.isPrivate()) throw new IllegalArgumentException();
PreparedStatement ps = null;
try {
String sql = "UPDATE groups SET visibleToAll = ? WHERE groupId = ?";
ps = txn.prepareStatement(sql);
ps.setBoolean(1, all);
ps.setBytes(2, g.getBytes());
ps.setBytes(2, g.getId().getBytes());
int affected = ps.executeUpdate();
if(affected > 1) throw new DbStateException();
ps.close();

View File

@@ -83,7 +83,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
public DatabaseComponentTest() {
groupId = new GroupId(TestUtils.getRandomId());
group = new Group(groupId, "Group", new byte[GROUP_SALT_LENGTH], true);
group = new Group(groupId, "Group", new byte[GROUP_SALT_LENGTH], false);
authorId = new AuthorId(TestUtils.getRandomId());
author = new Author(authorId, "Alice", new byte[MAX_PUBLIC_KEY_LENGTH]);
localAuthorId = new AuthorId(TestUtils.getRandomId());
@@ -465,7 +465,9 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
} catch(NoSuchContactException expected) {}
try {
db.setInboxGroup(contactId, group);
Group privateGroup = new Group(groupId, "Group",
new byte[GROUP_SALT_LENGTH], true);
db.setInboxGroup(contactId, privateGroup);
fail();
} catch(NoSuchContactException expected) {}
@@ -557,7 +559,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
} catch(NoSuchSubscriptionException expected) {}
try {
db.setVisibility(groupId, Collections.<ContactId>emptyList());
db.setVisibility(group, Collections.<ContactId>emptyList());
fail();
} catch(NoSuchSubscriptionException expected) {}
@@ -1337,8 +1339,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
will(returnValue(both));
oneOf(database).getContactIds(txn);
will(returnValue(both));
oneOf(database).removeVisibility(txn, contactId1, groupId);
oneOf(database).setVisibleToAll(txn, groupId, false);
oneOf(database).removeVisibility(txn, contactId1, group);
oneOf(database).setVisibleToAll(txn, group, false);
oneOf(database).commitTransaction(txn);
oneOf(listener).eventOccurred(with(any(
LocalSubscriptionsUpdatedEvent.class)));
@@ -1347,7 +1349,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
shutdown);
db.addListener(listener);
db.setVisibility(groupId, Arrays.asList(contactId));
db.setVisibility(group, Arrays.asList(contactId));
context.assertIsSatisfied();
}
@@ -1372,14 +1374,14 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
will(returnValue(both));
oneOf(database).getContactIds(txn);
will(returnValue(both));
oneOf(database).setVisibleToAll(txn, groupId, false);
oneOf(database).setVisibleToAll(txn, group, false);
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner,
shutdown);
db.addListener(listener);
db.setVisibility(groupId, both);
db.setVisibility(group, both);
context.assertIsSatisfied();
}
@@ -1405,8 +1407,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
will(returnValue(Collections.emptyList()));
oneOf(database).getContactIds(txn);
will(returnValue(both));
oneOf(database).addVisibility(txn, contactId, groupId);
oneOf(database).setVisibleToAll(txn, groupId, false);
oneOf(database).addVisibility(txn, contactId, group);
oneOf(database).setVisibleToAll(txn, group, false);
oneOf(database).commitTransaction(txn);
oneOf(listener).eventOccurred(with(any(
LocalSubscriptionsUpdatedEvent.class)));
@@ -1415,12 +1417,12 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
will(returnValue(txn));
oneOf(database).containsGroup(txn, groupId);
will(returnValue(true));
oneOf(database).setVisibleToAll(txn, groupId, true);
oneOf(database).setVisibleToAll(txn, group, true);
oneOf(database).getVisibility(txn, groupId);
will(returnValue(Arrays.asList(contactId)));
oneOf(database).getContactIds(txn);
will(returnValue(both));
oneOf(database).addVisibility(txn, contactId1, groupId);
oneOf(database).addVisibility(txn, contactId1, group);
oneOf(database).commitTransaction(txn);
oneOf(listener).eventOccurred(with(any(
LocalSubscriptionsUpdatedEvent.class)));
@@ -1429,8 +1431,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
shutdown);
db.addListener(listener);
db.setVisibility(groupId, Arrays.asList(contactId));
db.setVisibleToAll(groupId, true);
db.setVisibility(group, Arrays.asList(contactId));
db.setVisibleToAll(group, true);
context.assertIsSatisfied();
}

View File

@@ -166,7 +166,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
db.setGroups(txn, contactId, Arrays.asList(group), 1);
db.addMessage(txn, message, false);
@@ -203,7 +203,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
db.addMessage(txn, message, false);
db.addStatus(txn, contactId, messageId, false);
@@ -240,7 +240,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
db.setGroups(txn, contactId, Arrays.asList(group), 1);
db.addMessage(txn, message, false);
db.addStatus(txn, contactId, messageId, false);
@@ -283,7 +283,7 @@ public class H2DatabaseTest extends BriarTestCase {
assertFalse(it.hasNext());
// Making the subscription visible should make the message sendable
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
assertTrue(db.containsSendableMessages(txn, contactId));
it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator();
assertTrue(it.hasNext());
@@ -356,7 +356,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
db.setGroups(txn, contactId, Arrays.asList(group), 1);
db.addMessage(txn, message, false);
db.addStatus(txn, contactId, messageId, false);
@@ -654,7 +654,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
db.setGroups(txn, contactId, Arrays.asList(group), 1);
// The message is not in the database
@@ -673,7 +673,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
db.setGroups(txn, contactId, Arrays.asList(group), 1);
db.addMessage(txn, message, false);
@@ -697,7 +697,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
db.setGroups(txn, contactId, Arrays.asList(group), 1);
db.setRetentionTime(txn, contactId, timestamp + 1, 1);
db.addMessage(txn, message, false);
@@ -721,7 +721,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
db.setGroups(txn, contactId, Arrays.asList(group), 1);
db.addMessage(txn, message, false);
@@ -746,7 +746,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
db.setGroups(txn, contactId, Arrays.asList(group), 1);
// The message is not in the database
@@ -784,7 +784,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
db.addMessage(txn, message, false);
db.addStatus(txn, contactId, messageId, false);
@@ -826,7 +826,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
db.setGroups(txn, contactId, Arrays.asList(group), 1);
db.addMessage(txn, message, false);
@@ -849,7 +849,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
db.setGroups(txn, contactId, Arrays.asList(group), 1);
db.addMessage(txn, message, false);
@@ -876,11 +876,11 @@ public class H2DatabaseTest extends BriarTestCase {
assertEquals(Collections.emptyList(), db.getVisibility(txn, groupId));
// Make the group visible to the contact
db.addVisibility(txn, contactId, groupId);
db.addVisibility(txn, contactId, group);
assertEquals(Arrays.asList(contactId), db.getVisibility(txn, groupId));
// Make the group invisible again
db.removeVisibility(txn, contactId, groupId);
db.removeVisibility(txn, contactId, group);
assertEquals(Collections.emptyList(), db.getVisibility(txn, groupId));
db.commitTransaction(txn);
@@ -1201,13 +1201,12 @@ public class H2DatabaseTest extends BriarTestCase {
// Make the groups visible to the contact
Collections.shuffle(groups);
for(Group g : groups) db.addVisibility(txn, contactId, g.getId());
for(Group g : groups) db.addVisibility(txn, contactId, g);
// Make some of the groups invisible to the contact and remove them all
Collections.shuffle(groups);
for(Group g : groups) {
if(Math.random() < 0.5)
db.removeVisibility(txn, contactId, g.getId());
if(Math.random() < 0.5) db.removeVisibility(txn, contactId, g);
db.removeGroup(txn, g.getId());
}
@@ -1572,7 +1571,7 @@ public class H2DatabaseTest extends BriarTestCase {
// Make the group visible to all contacts - it should be available,
// subscribed, visible to all
db.setVisibleToAll(txn, groupId, true);
db.setVisibleToAll(txn, group, true);
assertEquals(Arrays.asList(group), db.getGroups(txn));
it = db.getAvailableGroups(txn).iterator();
assertTrue(it.hasNext());