mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Added a flag for making groups visible to future contacts.
This commit is contained in:
@@ -344,11 +344,18 @@ public interface DatabaseComponent {
|
||||
|
||||
/**
|
||||
* Makes the given group visible to the given set of contacts and invisible
|
||||
* to any other contacts.
|
||||
* to any other current or future contacts.
|
||||
*/
|
||||
void setVisibility(GroupId 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.
|
||||
*/
|
||||
void setVisibleToAll(GroupId g, boolean visible) throws DbException;
|
||||
|
||||
/**
|
||||
* Subscribes to the given group, or returns false if the user already has
|
||||
* the maximum number of subscriptions.
|
||||
|
||||
@@ -791,6 +791,13 @@ interface Database<T> {
|
||||
void setTransportUpdateAcked(T txn, ContactId c, TransportId t,
|
||||
long version) throws DbException;
|
||||
|
||||
/**
|
||||
* Makes the given group visible or invisible to future contacts by default.
|
||||
* <p>
|
||||
* Locking: subscription write.
|
||||
*/
|
||||
void setVisibleToAll(T txn, GroupId g, boolean visible) throws DbException;
|
||||
|
||||
/**
|
||||
* Updates the expiry times of the given messages with respect to the given
|
||||
* contact, using the given transmission counts and the latency of the
|
||||
|
||||
@@ -1982,22 +1982,61 @@ DatabaseCleaner.Callback {
|
||||
if(!db.containsSubscription(txn, g))
|
||||
throw new NoSuchSubscriptionException();
|
||||
// Use HashSets for O(1) lookups, O(n) overall running time
|
||||
HashSet<ContactId> newVisible =
|
||||
new HashSet<ContactId>(visible);
|
||||
HashSet<ContactId> oldVisible =
|
||||
new HashSet<ContactId>(db.getVisibility(txn, g));
|
||||
HashSet<ContactId> now = new HashSet<ContactId>(visible);
|
||||
Collection<ContactId> before = db.getVisibility(txn, g);
|
||||
before = new HashSet<ContactId>(before);
|
||||
// Set the group's visibility for each current contact
|
||||
for(ContactId c : db.getContactIds(txn)) {
|
||||
boolean then = oldVisible.contains(c);
|
||||
boolean now = newVisible.contains(c);
|
||||
if(!then && now) {
|
||||
boolean wasBefore = before.contains(c);
|
||||
boolean isNow = now.contains(c);
|
||||
if(!wasBefore && isNow) {
|
||||
db.addVisibility(txn, c, g);
|
||||
affected.add(c);
|
||||
} else if(then && !now) {
|
||||
} else if(wasBefore && !isNow) {
|
||||
db.removeVisibility(txn, c, g);
|
||||
affected.add(c);
|
||||
}
|
||||
}
|
||||
// Make the group invisible to future contacts
|
||||
db.setVisibleToAll(txn, g, false);
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
subscriptionLock.writeLock().unlock();
|
||||
}
|
||||
} finally {
|
||||
contactLock.readLock().unlock();
|
||||
}
|
||||
if(!affected.isEmpty())
|
||||
callListeners(new LocalSubscriptionsUpdatedEvent(affected));
|
||||
}
|
||||
|
||||
public void setVisibleToAll(GroupId g, boolean visible) throws DbException {
|
||||
Collection<ContactId> affected = new ArrayList<ContactId>();
|
||||
contactLock.readLock().lock();
|
||||
try {
|
||||
subscriptionLock.writeLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
if(!db.containsSubscription(txn, g))
|
||||
throw new NoSuchSubscriptionException();
|
||||
// Make the group visible or invisible to future contacts
|
||||
db.setVisibleToAll(txn, g, visible);
|
||||
if(visible) {
|
||||
// Make the group visible to all current contacts
|
||||
Collection<ContactId> before = db.getVisibility(txn, g);
|
||||
before = new HashSet<ContactId>(before);
|
||||
for(ContactId c : db.getContactIds(txn)) {
|
||||
if(!before.contains(c)) {
|
||||
db.addVisibility(txn, c, g);
|
||||
affected.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
|
||||
@@ -103,6 +103,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
+ " (groupId HASH NOT NULL,"
|
||||
+ " name VARCHAR NOT NULL,"
|
||||
+ " publicKey BINARY," // Null for unrestricted groups
|
||||
+ " visibleToAll BOOLEAN NOT NULL,"
|
||||
+ " PRIMARY KEY (groupId))";
|
||||
|
||||
// Locking: subscription
|
||||
@@ -573,6 +574,27 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
// Make groups that are visible to everyone visible to this contact
|
||||
sql = "SELECT groupId FROM groups WHERE visibleToAll = TRUE";
|
||||
ps = txn.prepareStatement(sql);
|
||||
rs = ps.executeQuery();
|
||||
Collection<byte[]> ids = new ArrayList<byte[]>();
|
||||
while(rs.next()) ids.add(rs.getBytes(1));
|
||||
rs.close();
|
||||
ps.close();
|
||||
if(!ids.isEmpty()) {
|
||||
sql = "INSERT INTO groupVisibilities (contactId, groupId)"
|
||||
+ " VALUES (?, ?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
for(byte[] id : ids) {
|
||||
ps.setBytes(2, id);
|
||||
ps.addBatch();
|
||||
}
|
||||
affected = ps.executeUpdate();
|
||||
if(affected != ids.size()) throw new DbStateException();
|
||||
ps.close();
|
||||
}
|
||||
// Create a connection time row
|
||||
sql = "INSERT INTO connectionTimes (contactId, lastConnected)"
|
||||
+ " VALUES (?, ?)";
|
||||
@@ -893,8 +915,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
ps.close();
|
||||
if(count > MAX_SUBSCRIPTIONS) throw new DbStateException();
|
||||
if(count == MAX_SUBSCRIPTIONS) return false;
|
||||
sql = "INSERT INTO groups (groupId, name, publicKey)"
|
||||
+ " VALUES (?, ?, ?)";
|
||||
sql = "INSERT INTO groups (groupId, name, publicKey, visibleToAll)"
|
||||
+ " VALUES (?, ?, ?, FALSE)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, g.getId().getBytes());
|
||||
ps.setString(2, g.getName());
|
||||
@@ -3376,6 +3398,23 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public void setVisibleToAll(Connection txn, GroupId g, boolean visible)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
String sql = "UPDATE groups SET visibleToAll = ? WHERE groupId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBoolean(1, visible);
|
||||
ps.setBytes(2, g.getBytes());
|
||||
int affected = ps.executeUpdate();
|
||||
if(affected > 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch(SQLException e) {
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateExpiryTimes(Connection txn, ContactId c,
|
||||
Map<MessageId, Integer> sent, long maxLatency) throws DbException {
|
||||
long now = clock.currentTimeMillis();
|
||||
|
||||
@@ -1729,6 +1729,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
||||
oneOf(database).getContactIds(txn);
|
||||
will(returnValue(both));
|
||||
oneOf(database).removeVisibility(txn, contactId1, groupId);
|
||||
oneOf(database).setVisibleToAll(txn, groupId, false);
|
||||
oneOf(database).commitTransaction(txn);
|
||||
oneOf(listener).eventOccurred(with(any(
|
||||
LocalSubscriptionsUpdatedEvent.class)));
|
||||
@@ -1745,7 +1746,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
||||
@Test
|
||||
public void testNotChangingVisibilityDoesNotCallListeners()
|
||||
throws Exception {
|
||||
final ContactId contactId1 = new ContactId(234);
|
||||
final ContactId contactId1 = new ContactId(123);
|
||||
final Collection<ContactId> both = Arrays.asList(contactId, contactId1);
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -1762,6 +1763,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
||||
will(returnValue(both));
|
||||
oneOf(database).getContactIds(txn);
|
||||
will(returnValue(both));
|
||||
oneOf(database).setVisibleToAll(txn, groupId, false);
|
||||
oneOf(database).commitTransaction(txn);
|
||||
}});
|
||||
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||
@@ -1773,6 +1775,57 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSettingVisibleToAllTrueAffectsCurrentContacts()
|
||||
throws Exception {
|
||||
final ContactId contactId1 = new ContactId(123);
|
||||
final Collection<ContactId> both = Arrays.asList(contactId, contactId1);
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
final Database<Object> database = context.mock(Database.class);
|
||||
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
|
||||
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
final DatabaseListener listener = context.mock(DatabaseListener.class);
|
||||
context.checking(new Expectations() {{
|
||||
// setVisibility()
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
oneOf(database).containsSubscription(txn, groupId);
|
||||
will(returnValue(true));
|
||||
oneOf(database).getVisibility(txn, groupId);
|
||||
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).commitTransaction(txn);
|
||||
oneOf(listener).eventOccurred(with(any(
|
||||
LocalSubscriptionsUpdatedEvent.class)));
|
||||
// setVisibleToAll()
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
oneOf(database).containsSubscription(txn, groupId);
|
||||
will(returnValue(true));
|
||||
oneOf(database).setVisibleToAll(txn, groupId, 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).commitTransaction(txn);
|
||||
oneOf(listener).eventOccurred(with(any(
|
||||
LocalSubscriptionsUpdatedEvent.class)));
|
||||
}});
|
||||
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||
shutdown);
|
||||
|
||||
db.addListener(listener);
|
||||
db.setVisibility(groupId, Arrays.asList(contactId));
|
||||
db.setVisibleToAll(groupId, true);
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTemporarySecrets() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
|
||||
@@ -873,6 +873,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.addLocalAuthor(txn, localAuthor);
|
||||
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||
db.addSubscription(txn, group);
|
||||
db.addVisibility(txn, contactId, groupId);
|
||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
||||
|
||||
// The message is not in the database
|
||||
@@ -891,6 +892,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.addLocalAuthor(txn, localAuthor);
|
||||
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||
db.addSubscription(txn, group);
|
||||
db.addVisibility(txn, contactId, groupId);
|
||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
||||
db.addGroupMessage(txn, message);
|
||||
|
||||
@@ -915,6 +917,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.addLocalAuthor(txn, localAuthor);
|
||||
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||
db.addSubscription(txn, group);
|
||||
db.addVisibility(txn, contactId, groupId);
|
||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
||||
db.addGroupMessage(txn, message);
|
||||
|
||||
@@ -1028,6 +1031,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.addLocalAuthor(txn, localAuthor);
|
||||
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||
db.addSubscription(txn, group);
|
||||
db.addVisibility(txn, contactId, groupId);
|
||||
db.addGroupMessage(txn, message);
|
||||
db.addStatus(txn, contactId, messageId, false);
|
||||
|
||||
@@ -1048,8 +1052,8 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.addLocalAuthor(txn, localAuthor);
|
||||
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
|
||||
db.addSubscription(txn, group);
|
||||
db.addGroupMessage(txn, message);
|
||||
db.setSubscriptions(txn, contactId, Arrays.asList(group), 1);
|
||||
db.addGroupMessage(txn, message);
|
||||
db.addStatus(txn, contactId, messageId, false);
|
||||
|
||||
// The subscription is not visible
|
||||
|
||||
Reference in New Issue
Block a user