Removed public/private groups from the wire protocol.

The distinction between inbox groups and other groups can be maintained
internally, there's no need to represent it on the wire.
This commit is contained in:
akwizgran
2013-12-20 13:32:36 +00:00
parent e8d864c004
commit 51b3a10be2
21 changed files with 139 additions and 199 deletions

View File

@@ -77,7 +77,7 @@ SelectContactsDialog.Listener {
setTitle(name);
b = i.getByteArrayExtra("net.sf.briar.GROUP_SALT");
if(b == null) throw new IllegalStateException();
group = new Group(id, name, b, false);
group = new Group(id, name, b);
subscribed = i.getBooleanExtra("net.sf.briar.SUBSCRIBED", false);
boolean all = i.getBooleanExtra("net.sf.briar.VISIBLE_TO_ALL", false);
@@ -208,8 +208,8 @@ SelectContactsDialog.Listener {
long now = System.currentTimeMillis();
if(subscribe) {
if(!wasSubscribed) db.addGroup(group);
db.setVisibleToAll(group, all);
if(!all) db.setVisibility(group, visible);
db.setVisibleToAll(group.getId(), all);
if(!all) db.setVisibility(group.getId(), visible);
} else if(wasSubscribed) {
db.removeGroup(group);
}

View File

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

View File

@@ -15,6 +15,8 @@ import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP_1;
import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
@@ -58,6 +60,9 @@ OnItemClickListener {
private static final Logger LOG =
Logger.getLogger(GroupListActivity.class.getName());
private final Map<GroupId,GroupId> groups =
new ConcurrentHashMap<GroupId,GroupId>();
private GroupListAdapter adapter = null;
private ListView list = null;
private ListLoadingProgressBar loading = null;
@@ -140,7 +145,6 @@ OnItemClickListener {
long now = System.currentTimeMillis();
for(GroupStatus s : db.getAvailableGroups()) {
Group g = s.getGroup();
if(g.isPrivate()) continue;
if(s.isSubscribed()) {
try {
Collection<MessageHeader> headers =
@@ -173,6 +177,7 @@ OnItemClickListener {
private void clearHeaders() {
runOnUiThread(new Runnable() {
public void run() {
groups.clear();
list.setVisibility(GONE);
loading.setVisibility(VISIBLE);
adapter.clear();
@@ -185,10 +190,12 @@ OnItemClickListener {
final Collection<MessageHeader> headers) {
runOnUiThread(new Runnable() {
public void run() {
GroupId id = g.getId();
groups.put(id, id);
list.setVisibility(VISIBLE);
loading.setVisibility(GONE);
// Remove the old item, if any
GroupListItem item = findGroup(g.getId());
GroupListItem item = findGroup(id);
if(item != null) adapter.remove(item);
// Add a new item
adapter.add(new GroupListItem(g, headers));
@@ -243,7 +250,7 @@ OnItemClickListener {
public void eventOccurred(DatabaseEvent e) {
if(e instanceof MessageAddedEvent) {
Group g = ((MessageAddedEvent) e).getGroup();
if(!g.isPrivate()) {
if(groups.containsKey(g.getId())) {
if(LOG.isLoggable(INFO)) LOG.info("Message added, reloading");
loadHeaders(g);
}
@@ -259,7 +266,7 @@ OnItemClickListener {
loadHeaders();
} else if(e instanceof SubscriptionRemovedEvent) {
Group g = ((SubscriptionRemovedEvent) e).getGroup();
if(!g.isPrivate()) {
if(groups.containsKey(g.getId())) {
// Reload the group, expecting NoSuchSubscriptionException
if(LOG.isLoggable(INFO)) LOG.info("Group removed, reloading");
loadHeaders(g);
@@ -299,6 +306,7 @@ OnItemClickListener {
public void run() {
GroupListItem item = findGroup(g);
if(item != null) {
groups.remove(g);
adapter.remove(item);
adapter.notifyDataSetChanged();
selectFirstUnread();
@@ -314,10 +322,8 @@ OnItemClickListener {
lifecycleManager.waitForDatabase();
int available = 0;
long now = System.currentTimeMillis();
for(GroupStatus s : db.getAvailableGroups()) {
if(!s.isSubscribed() && !s.getGroup().isPrivate())
available++;
}
for(GroupStatus s : db.getAvailableGroups())
if(!s.isSubscribed()) available++;
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Loading available took " + duration + " ms");

View File

@@ -5,7 +5,6 @@ import static java.util.logging.Level.WARNING;
import static net.sf.briar.android.groups.ManageGroupsItem.NONE;
import static net.sf.briar.android.util.CommonLayoutParams.MATCH_MATCH;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.concurrent.Executor;
@@ -76,10 +75,7 @@ implements DatabaseListener, OnItemClickListener {
try {
lifecycleManager.waitForDatabase();
long now = System.currentTimeMillis();
Collection<GroupStatus> available =
new ArrayList<GroupStatus>();
for(GroupStatus s : db.getAvailableGroups())
if(!s.getGroup().isPrivate()) available.add(s);
Collection<GroupStatus> available = db.getAvailableGroups();
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Load took " + duration + " ms");

View File

@@ -35,6 +35,7 @@ import net.sf.briar.api.db.DbException;
import net.sf.briar.api.lifecycle.LifecycleManager;
import net.sf.briar.api.messaging.Group;
import net.sf.briar.api.messaging.GroupId;
import net.sf.briar.api.messaging.GroupStatus;
import net.sf.briar.api.messaging.Message;
import net.sf.briar.api.messaging.MessageFactory;
import net.sf.briar.api.messaging.MessageId;
@@ -215,8 +216,8 @@ implements OnItemSelectedListener, OnClickListener {
lifecycleManager.waitForDatabase();
long now = System.currentTimeMillis();
Collection<Group> groups = new ArrayList<Group>();
for(Group g : db.getGroups())
if(!g.isPrivate()) groups.add(g);
for(GroupStatus s : db.getAvailableGroups())
if(s.isSubscribed()) groups.add(s.getGroup());
long duration = System.currentTimeMillis() - now;
if(LOG.isLoggable(INFO))
LOG.info("Loading groups took " + duration + " ms");

View File

@@ -160,7 +160,10 @@ public interface DatabaseComponent {
Collection<TransportUpdate> generateTransportUpdates(ContactId c,
long maxLatency) throws DbException;
/** Returns the status of all groups to which the user can subscribe. */
/**
* Returns the status of all groups to which the user subscribes or can
* subscribe, excluding inbox groups.
*/
Collection<GroupStatus> getAvailableGroups() throws DbException;
/** Returns the configuration for the given transport. */
@@ -326,8 +329,8 @@ public interface DatabaseComponent {
long centre, byte[] bitmap) throws DbException;
/**
* Makes a private group visible to the given contact, adds it to the
* contact's subscriptions, and sets it as the inbox group for the contact.
* Makes a group visible to the given contact, adds it to the contact's
* subscriptions, and sets it as the inbox group for the contact.
*/
public void setInboxGroup(ContactId c, Group g) throws DbException;
@@ -348,15 +351,15 @@ public interface DatabaseComponent {
void setSeen(ContactId c, Collection<MessageId> seen) throws DbException;
/**
* Makes a public group visible to the given set of contacts and invisible
* to any other current or future contacts.
* Makes a group visible to the given set of contacts and invisible to any
* other current or future contacts.
*/
void setVisibility(Group g, Collection<ContactId> visible)
void setVisibility(GroupId g, Collection<ContactId> visible)
throws DbException;
/**
* Makes a public group visible to all current and future contacts, or
* invisible to future contacts.
* Makes a group visible to all current and future contacts, or invisible
* to future contacts.
*/
void setVisibleToAll(Group g, boolean all) throws DbException;
void setVisibleToAll(GroupId g, boolean all) throws DbException;
}

View File

@@ -6,13 +6,11 @@ public class Group {
private final GroupId id;
private final String name;
private final byte[] salt;
private final boolean isPrivate;
public Group(GroupId id, String name, byte[] salt, boolean isPrivate) {
public Group(GroupId id, String name, byte[] salt) {
this.id = id;
this.name = name;
this.salt = salt;
this.isPrivate = isPrivate;
}
/** Returns the group's unique identifier. */
@@ -33,11 +31,6 @@ public class Group {
return salt;
}
/** Returns true if the group is private. */
public boolean isPrivate() {
return isPrivate;
}
@Override
public int hashCode() {
return id.hashCode();

View File

@@ -3,8 +3,8 @@ package net.sf.briar.api.messaging;
public interface GroupFactory {
/** Creates a group with the given name and a random salt. */
Group createGroup(String name, boolean isPrivate);
Group createGroup(String name);
/** Creates a group with the given name and salt. */
Group createGroup(String name, byte[] salt, boolean isPrivate);
Group createGroup(String name, byte[] salt);
}

View File

@@ -152,11 +152,11 @@ interface Database<T> {
throws DbException;
/**
* Makes a public group visible to the given contact.
* Makes a group visible to the given contact.
* <p>
* Locking: subscription write.
*/
void addVisibility(T txn, ContactId c, Group g) throws DbException;
void addVisibility(T txn, ContactId c, GroupId g) throws DbException;
/**
* Returns true if the database contains the given contact.
@@ -217,7 +217,8 @@ interface Database<T> {
throws DbException;
/**
* Returns the status of all groups to which the user can subscribe.
* Returns the status of all groups to which the user subscribes or can
* subscribe, excluding inbox groups.
* <p>
* Locking: subscription read.
*/
@@ -522,15 +523,6 @@ interface Database<T> {
*/
Collection<ContactId> getVisibility(T txn, GroupId g) throws DbException;
/**
* Returns the IDs of all private groups that are visible to the given
* contact.
* <p>
* Locking: subscription read.
*/
Collection<GroupId> getVisiblePrivateGroups(T txn, ContactId c)
throws DbException;
/**
* Increments the outgoing connection counter for the given endpoint
* in the given rotation period and returns the old value, or -1 if the
@@ -616,11 +608,11 @@ interface Database<T> {
void removeTransport(T txn, TransportId t) throws DbException;
/**
* Makes a public group invisible to the given contact.
* Makes a group invisible to the given contact.
* <p>
* Locking: subscription write.
*/
void removeVisibility(T txn, ContactId c, Group g) throws DbException;
void removeVisibility(T txn, ContactId c, GroupId g) throws DbException;
/**
* Sets the connection reordering window for the given endpoint in the
@@ -642,8 +634,8 @@ interface Database<T> {
long version) throws DbException;
/**
* Makes a private group visible to the given contact, adds it to the
* contact's subscriptions, and sets it as the inbox group for the contact.
* Makes a group visible to the given contact, adds it to the contact's
* subscriptions, and sets it as the inbox group for the contact.
* <p>
* Locking: contact read, message write, subscription write.
*/
@@ -732,11 +724,11 @@ interface Database<T> {
long version) throws DbException;
/**
* Makes a public group visible or invisible to future contacts by default.
* Makes a group visible or invisible to future contacts by default.
* <p>
* Locking: subscription write.
*/
void setVisibleToAll(T txn, Group g, boolean all) throws DbException;
void setVisibleToAll(T txn, GroupId g, boolean all) throws DbException;
/**
* Updates the expiry times of the given messages with respect to the given

View File

@@ -1770,7 +1770,6 @@ DatabaseCleaner.Callback {
}
public void setInboxGroup(ContactId c, Group g) throws DbException {
if(!g.isPrivate()) throw new IllegalArgumentException();
contactLock.readLock().lock();
try {
messageLock.writeLock().lock();
@@ -1871,9 +1870,8 @@ DatabaseCleaner.Callback {
}
}
public void setVisibility(Group g, Collection<ContactId> visible)
public void setVisibility(GroupId g, Collection<ContactId> visible)
throws DbException {
if(g.isPrivate()) throw new IllegalArgumentException();
Collection<ContactId> affected = new ArrayList<ContactId>();
contactLock.readLock().lock();
try {
@@ -1881,12 +1879,11 @@ DatabaseCleaner.Callback {
try {
T txn = db.startTransaction();
try {
if(!db.containsGroup(txn, g.getId()))
if(!db.containsGroup(txn, g))
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.getId());
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)) {
@@ -1917,8 +1914,7 @@ DatabaseCleaner.Callback {
callListeners(new LocalSubscriptionsUpdatedEvent(affected));
}
public void setVisibleToAll(Group g, boolean all) throws DbException {
if(g.isPrivate()) throw new IllegalArgumentException();
public void setVisibleToAll(GroupId g, boolean all) throws DbException {
Collection<ContactId> affected = new ArrayList<ContactId>();
contactLock.readLock().lock();
try {
@@ -1926,14 +1922,13 @@ DatabaseCleaner.Callback {
try {
T txn = db.startTransaction();
try {
if(!db.containsGroup(txn, g.getId()))
if(!db.containsGroup(txn, g))
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.getId());
Collection<ContactId> before = db.getVisibility(txn, g);
before = new HashSet<ContactId>(before);
for(ContactId c : db.getContactIds(txn)) {
if(!before.contains(c)) {

View File

@@ -88,7 +88,6 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " (groupId HASH NOT NULL,"
+ " name VARCHAR NOT NULL,"
+ " salt BINARY NOT NULL,"
+ " private BOOLEAN NOT NULL,"
+ " visibleToAll BOOLEAN NOT NULL,"
+ " PRIMARY KEY (groupId))";
@@ -112,7 +111,6 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " groupId HASH NOT NULL," // Not a foreign key
+ " name VARCHAR NOT NULL,"
+ " salt BINARY NOT NULL,"
+ " private BOOLEAN NOT NULL,"
+ " PRIMARY KEY (contactId, groupId),"
+ " FOREIGN KEY (contactId)"
+ " REFERENCES contacts (contactId)"
@@ -646,13 +644,12 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null;
try {
String sql = "INSERT INTO groups"
+ " (groupId, name, salt, private, visibleToAll)"
+ " VALUES (?, ?, ?, ?, FALSE)";
+ " (groupId, name, salt, visibleToAll)"
+ " VALUES (?, ?, ?, FALSE)";
ps = txn.prepareStatement(sql);
ps.setBytes(1, g.getId().getBytes());
ps.setString(2, g.getName());
ps.setBytes(3, g.getSalt());
ps.setBoolean(4, g.isPrivate());
int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException();
ps.close();
@@ -900,9 +897,8 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public void addVisibility(Connection txn, ContactId c, Group g)
public void addVisibility(Connection txn, ContactId c, GroupId g)
throws DbException {
if(g.isPrivate()) throw new IllegalArgumentException();
PreparedStatement ps = null;
try {
String sql = "INSERT INTO groupVisibilities"
@@ -910,7 +906,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " VALUES (?, ?, FALSE)";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setBytes(2, g.getId().getBytes());
ps.setBytes(2, g.getBytes());
int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException();
ps.close();
@@ -1120,9 +1116,12 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null;
ResultSet rs = null;
try {
// Add all subscribed groups to the list
String sql = "SELECT groupId, name, salt, private, visibleToAll"
+ " FROM groups";
// Add all subscribed groups to the list, except inbox groups
String sql = "SELECT DISTINCT g.groupId, name, salt, visibleToAll"
+ " FROM groups AS g"
+ " LEFT OUTER JOIN groupVisibilities AS gv"
+ " ON g.groupId = gv.groupId"
+ " WHERE inbox = FALSE OR inbox IS NULL";
ps = txn.prepareStatement(sql);
rs = ps.executeQuery();
List<GroupStatus> groups = new ArrayList<GroupStatus>();
@@ -1130,15 +1129,14 @@ abstract class JdbcDatabase implements Database<Connection> {
GroupId id = new GroupId(rs.getBytes(1));
String name = rs.getString(2);
byte[] salt = rs.getBytes(3);
boolean isPrivate = rs.getBoolean(4);
Group group = new Group(id, name, salt, isPrivate);
boolean visibleToAll = rs.getBoolean(5);
Group group = new Group(id, name, salt);
boolean visibleToAll = rs.getBoolean(4);
groups.add(new GroupStatus(group, true, visibleToAll));
}
rs.close();
ps.close();
// Add all unsubscribed groups to the list
sql = "SELECT DISTINCT cg.groupId, cg.name, cg.salt, cg.private"
sql = "SELECT DISTINCT cg.groupId, cg.name, cg.salt"
+ " FROM contactGroups AS cg"
+ " LEFT OUTER JOIN groups AS g"
+ " ON cg.groupId = g.groupId"
@@ -1149,8 +1147,7 @@ abstract class JdbcDatabase implements Database<Connection> {
GroupId id = new GroupId(rs.getBytes(1));
String name = rs.getString(2);
byte[] salt = rs.getBytes(3);
boolean isPrivate = rs.getBoolean(4);
Group group = new Group(id, name, salt, isPrivate);
Group group = new Group(id, name, salt);
groups.add(new GroupStatus(group, false, false));
}
rs.close();
@@ -1313,18 +1310,16 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT name, salt, private FROM groups"
+ " WHERE groupId = ?";
String sql = "SELECT name, salt FROM groups WHERE groupId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, g.getBytes());
rs = ps.executeQuery();
if(!rs.next()) throw new DbStateException();
String name = rs.getString(1);
byte[] salt = rs.getBytes(2);
boolean isPrivate = rs.getBoolean(3);
rs.close();
ps.close();
return new Group(g, name, salt, isPrivate);
return new Group(g, name, salt);
} catch(SQLException e) {
tryToClose(rs);
tryToClose(ps);
@@ -1336,7 +1331,7 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT groupId, name, salt, private FROM groups";
String sql = "SELECT groupId, name, salt FROM groups";
ps = txn.prepareStatement(sql);
rs = ps.executeQuery();
List<Group> groups = new ArrayList<Group>();
@@ -1344,8 +1339,7 @@ abstract class JdbcDatabase implements Database<Connection> {
GroupId id = new GroupId(rs.getBytes(1));
String name = rs.getString(2);
byte[] salt = rs.getBytes(3);
boolean isPrivate = rs.getBoolean(4);
groups.add(new Group(id, name, salt, isPrivate));
groups.add(new Group(id, name, salt));
}
rs.close();
ps.close();
@@ -2085,14 +2079,13 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT g.groupId, name, salt, private,"
+ " localVersion, txCount"
String sql = "SELECT g.groupId, name, salt, localVersion, txCount"
+ " FROM groups AS g"
+ " JOIN groupVisibilities AS vis"
+ " ON g.groupId = vis.groupId"
+ " JOIN groupVersions AS ver"
+ " ON vis.contactId = ver.contactId"
+ " WHERE vis.contactId = ?"
+ " JOIN groupVisibilities AS gvis"
+ " ON g.groupId = gvis.groupId"
+ " JOIN groupVersions AS gver"
+ " ON gvis.contactId = gver.contactId"
+ " WHERE gvis.contactId = ?"
+ " AND localVersion > localAcked"
+ " AND expiry < ?";
ps = txn.prepareStatement(sql);
@@ -2106,10 +2099,9 @@ abstract class JdbcDatabase implements Database<Connection> {
GroupId id = new GroupId(rs.getBytes(1));
String name = rs.getString(2);
byte[] salt = rs.getBytes(3);
boolean isPrivate = rs.getBoolean(4);
groups.add(new Group(id, name, salt, isPrivate));
version = rs.getLong(5);
txCount = rs.getInt(6);
groups.add(new Group(id, name, salt));
version = rs.getLong(4);
txCount = rs.getInt(5);
}
rs.close();
ps.close();
@@ -2335,32 +2327,6 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public Collection<GroupId> getVisiblePrivateGroups(Connection txn,
ContactId c) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT g.groupId"
+ " FROM groups AS g"
+ " JOIN groupVisibilities AS gv"
+ " ON g.groupId = gv.groupId"
+ " WHERE contactId = ?"
+ " AND private = TRUE";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
rs = ps.executeQuery();
List<GroupId> visible = new ArrayList<GroupId>();
while(rs.next()) visible.add(new GroupId(rs.getBytes(1)));
rs.close();
ps.close();
return Collections.unmodifiableList(visible);
} catch(SQLException e) {
tryToClose(rs);
tryToClose(ps);
throw new DbException(e);
}
}
public long incrementConnectionCounter(Connection txn, ContactId c,
TransportId t, long period) throws DbException {
PreparedStatement ps = null;
@@ -2619,16 +2585,15 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public void removeVisibility(Connection txn, ContactId c, Group g)
public void removeVisibility(Connection txn, ContactId c, GroupId 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.getId().getBytes());
ps.setBytes(2, g.getBytes());
int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException();
ps.close();
@@ -2694,15 +2659,14 @@ abstract class JdbcDatabase implements Database<Connection> {
// Store the new subscriptions, if any
if(groups.isEmpty()) return true;
sql = "INSERT INTO contactGroups"
+ " (contactId, groupId, name, salt, private)"
+ " VALUES (?, ?, ?, ?, ?)";
+ " (contactId, groupId, name, salt)"
+ " VALUES (?, ?, ?, ?)";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
for(Group g : groups) {
ps.setBytes(2, g.getId().getBytes());
ps.setString(3, g.getName());
ps.setBytes(4, g.getSalt());
ps.setBoolean(5, g.isPrivate());
ps.addBatch();
}
int[] batchAffected = ps.executeBatch();
@@ -2740,7 +2704,6 @@ abstract class JdbcDatabase implements Database<Connection> {
public void setInboxGroup(Connection txn, ContactId c, Group g)
throws DbException {
if(!g.isPrivate()) throw new IllegalArgumentException();
PreparedStatement ps = null;
try {
// Unset any existing inbox group for the contact
@@ -2765,14 +2728,13 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
// Add the group to the contact's subscriptions
sql = "INSERT INTO contactGroups"
+ " (contactId, groupId, name, salt, private)"
+ " VALUES (?, ?, ?, ?, ?)";
+ " (contactId, groupId, name, salt)"
+ " VALUES (?, ?, ?, ?)";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setBytes(2, g.getId().getBytes());
ps.setString(3, g.getName());
ps.setBytes(4, g.getSalt());
ps.setBoolean(5, g.isPrivate());
affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException();
ps.close();
@@ -3061,15 +3023,14 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
public void setVisibleToAll(Connection txn, Group g, boolean all)
public void setVisibleToAll(Connection txn, GroupId 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.getId().getBytes());
ps.setBytes(2, g.getBytes());
int affected = ps.executeUpdate();
if(affected > 1) throw new DbStateException();
ps.close();

View File

@@ -274,7 +274,7 @@ abstract class Connector extends Thread {
contactId = db.addContact(remoteAuthor, localAuthor.getId());
// Create and store the inbox group
byte[] salt = crypto.deriveGroupSalt(secret);
Group inbox = groupFactory.createGroup("Inbox", salt, true);
Group inbox = groupFactory.createGroup("Inbox", salt);
db.addGroup(inbox);
db.setInboxGroup(contactId, inbox);
// Store the remote transport properties

View File

@@ -27,20 +27,19 @@ class GroupFactoryImpl implements GroupFactory {
this.writerFactory = writerFactory;
}
public Group createGroup(String name, boolean isPrivate) {
public Group createGroup(String name) {
byte[] salt = new byte[GROUP_SALT_LENGTH];
crypto.getSecureRandom().nextBytes(salt);
return createGroup(name, salt, isPrivate);
return createGroup(name, salt);
}
public Group createGroup(String name, byte[] salt, boolean isPrivate) {
public Group createGroup(String name, byte[] salt) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer w = writerFactory.createWriter(out);
try {
w.writeStructStart(GROUP);
w.writeString(name);
w.writeBytes(salt);
w.writeBoolean(isPrivate);
w.writeStructEnd();
} catch(IOException e) {
// Shouldn't happen with ByteArrayOutputStream
@@ -49,6 +48,6 @@ class GroupFactoryImpl implements GroupFactory {
MessageDigest messageDigest = crypto.getMessageDigest();
messageDigest.update(out.toByteArray());
GroupId id = new GroupId(messageDigest.digest());
return new Group(id, name, salt, isPrivate);
return new Group(id, name, salt);
}
}

View File

@@ -31,11 +31,10 @@ class GroupReader implements StructReader<Group> {
byte[] publicKey = null;
if(r.hasNull()) r.readNull();
else publicKey = r.readBytes(MAX_PUBLIC_KEY_LENGTH);
boolean isPrivate = r.readBoolean();
r.readStructEnd();
r.removeConsumer(digesting);
// Build and return the group
GroupId id = new GroupId(messageDigest.digest());
return new Group(id, name, publicKey, isPrivate);
return new Group(id, name, publicKey);
}
}

View File

@@ -122,7 +122,6 @@ class MessageFactoryImpl implements MessageFactory {
w.writeStructStart(GROUP);
w.writeString(g.getName());
w.writeBytes(g.getSalt());
w.writeBoolean(g.isPrivate());
w.writeStructEnd();
}

View File

@@ -129,7 +129,6 @@ class PacketWriterImpl implements PacketWriter {
w.writeStructStart(GROUP);
w.writeString(g.getName());
w.writeBytes(g.getSalt());
w.writeBoolean(g.isPrivate());
w.writeStructEnd();
}
w.writeListEnd();

View File

@@ -95,7 +95,7 @@ public class ProtocolIntegrationTest extends BriarTestCase {
new Random().nextBytes(secret);
// Create a group
GroupFactory groupFactory = i.getInstance(GroupFactory.class);
group = groupFactory.createGroup("Group", false);
group = groupFactory.createGroup("Group");
// Create an author
AuthorFactory authorFactory = i.getInstance(AuthorFactory.class);
CryptoComponent crypto = i.getInstance(CryptoComponent.class);

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

View File

@@ -70,7 +70,7 @@ public class H2DatabaseTest extends BriarTestCase {
public H2DatabaseTest() throws Exception {
groupId = new GroupId(TestUtils.getRandomId());
group = new Group(groupId, "Group", new byte[GROUP_SALT_LENGTH], false);
group = new Group(groupId, "Group", new byte[GROUP_SALT_LENGTH]);
authorId = new AuthorId(TestUtils.getRandomId());
author = new Author(authorId, "Alice", new byte[MAX_PUBLIC_KEY_LENGTH]);
localAuthorId = new AuthorId(TestUtils.getRandomId());
@@ -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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
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, group);
db.addVisibility(txn, contactId, groupId);
assertEquals(Arrays.asList(contactId), db.getVisibility(txn, groupId));
// Make the group invisible again
db.removeVisibility(txn, contactId, group);
db.removeVisibility(txn, contactId, groupId);
assertEquals(Collections.emptyList(), db.getVisibility(txn, groupId));
db.commitTransaction(txn);
@@ -934,7 +934,7 @@ public class H2DatabaseTest extends BriarTestCase {
throws Exception {
GroupId groupId1 = new GroupId(TestUtils.getRandomId());
Group group1 = new Group(groupId1, "Another group",
new byte[GROUP_SALT_LENGTH], false);
new byte[GROUP_SALT_LENGTH]);
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
@@ -1134,7 +1134,7 @@ public class H2DatabaseTest extends BriarTestCase {
db.addGroup(txn, group);
GroupId groupId1 = new GroupId(TestUtils.getRandomId());
Group group1 = new Group(groupId1, "Another group",
new byte[GROUP_SALT_LENGTH], false);
new byte[GROUP_SALT_LENGTH]);
db.addGroup(txn, group1);
// Store two messages in the first group
@@ -1188,7 +1188,7 @@ public class H2DatabaseTest extends BriarTestCase {
for(int i = 0; i < 100; i++) {
GroupId id = new GroupId(TestUtils.getRandomId());
String name = "Group " + i;
groups.add(new Group(id, name, new byte[GROUP_SALT_LENGTH], false));
groups.add(new Group(id, name, new byte[GROUP_SALT_LENGTH]));
}
Database<Connection> db = open(false);
@@ -1201,12 +1201,13 @@ public class H2DatabaseTest extends BriarTestCase {
// Make the groups visible to the contact
Collections.shuffle(groups);
for(Group g : groups) db.addVisibility(txn, contactId, g);
for(Group g : groups) db.addVisibility(txn, contactId, g.getId());
// 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);
if(Math.random() < 0.5)
db.removeVisibility(txn, contactId, g.getId());
db.removeGroup(txn, g.getId());
}
@@ -1571,7 +1572,7 @@ public class H2DatabaseTest extends BriarTestCase {
// Make the group visible to all contacts - it should be available,
// subscribed, visible to all
db.setVisibleToAll(txn, group, true);
db.setVisibleToAll(txn, groupId, true);
assertEquals(Arrays.asList(group), db.getGroups(txn));
it = db.getAvailableGroups(txn).iterator();
assertTrue(it.hasNext());
@@ -1636,10 +1637,8 @@ public class H2DatabaseTest extends BriarTestCase {
// Add a contact and an inbox group - no headers should be returned
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
Group inbox = new Group(groupId, "Group", new byte[GROUP_SALT_LENGTH],
true);
db.addGroup(txn, inbox);
db.setInboxGroup(txn, contactId, inbox);
db.addGroup(txn, group);
db.setInboxGroup(txn, contactId, group);
assertEquals(Collections.emptyList(),
db.getInboxMessageHeaders(txn, contactId));

View File

@@ -121,7 +121,7 @@ public class ConstantsTest extends BriarTestCase {
MessageId parent = new MessageId(TestUtils.getRandomId());
// Create a maximum-length group
String groupName = TestUtils.createRandomString(MAX_GROUP_NAME_LENGTH);
Group group = groupFactory.createGroup(groupName, false);
Group group = groupFactory.createGroup(groupName);
// Create a maximum-length author
String authorName =
TestUtils.createRandomString(MAX_AUTHOR_NAME_LENGTH);
@@ -180,7 +180,7 @@ public class ConstantsTest extends BriarTestCase {
Collection<Group> groups = new ArrayList<Group>();
for(int i = 0; i < MAX_SUBSCRIPTIONS; i++) {
String name = TestUtils.createRandomString(MAX_GROUP_NAME_LENGTH);
groups.add(groupFactory.createGroup(name, false));
groups.add(groupFactory.createGroup(name));
}
// Create a maximum-length subscription update
SubscriptionUpdate u = new SubscriptionUpdate(groups, Long.MAX_VALUE);

View File

@@ -69,7 +69,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
public SimplexMessagingIntegrationTest() throws Exception {
GroupId 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]);
transportId = new TransportId(TestUtils.getRandomId());
// Create matching secrets for Alice and Bob
initialSecret = new byte[32];