mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 12:19:54 +01:00
Removed restricted groups (may be restored after beta testing).
This commit is contained in:
@@ -18,7 +18,6 @@ import net.sf.briar.api.db.PrivateMessageHeader;
|
||||
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.LocalGroup;
|
||||
import net.sf.briar.api.messaging.Message;
|
||||
import net.sf.briar.api.messaging.MessageId;
|
||||
import net.sf.briar.api.messaging.Rating;
|
||||
@@ -112,14 +111,6 @@ interface Database<T> {
|
||||
*/
|
||||
void addLocalAuthor(T txn, LocalAuthor a) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a restricted group to which the user can post messages. Storing
|
||||
* a group does not create a subscription to it.
|
||||
* <p>
|
||||
* Locking: identity write.
|
||||
*/
|
||||
void addLocalGroup(T txn, LocalGroup g) throws DbException;
|
||||
|
||||
/**
|
||||
* Records a received message as needing to be acknowledged.
|
||||
* <p>
|
||||
@@ -192,14 +183,6 @@ interface Database<T> {
|
||||
*/
|
||||
boolean containsContact(T txn, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given restricted group to
|
||||
* which the user can post messages.
|
||||
* <p>
|
||||
* Locking: identity read.
|
||||
*/
|
||||
boolean containsLocalGroup(T txn, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given message.
|
||||
* <p>
|
||||
@@ -301,6 +284,14 @@ interface Database<T> {
|
||||
*/
|
||||
MessageId getGroupMessageParent(T txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the IDs of all group messages posted by the given author.
|
||||
* <p>
|
||||
* Locking: message read.
|
||||
*/
|
||||
Collection<MessageId> getGroupMessages(T txn, AuthorId a)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the time at which a connection to each contact was last opened
|
||||
* or closed.
|
||||
@@ -323,13 +314,6 @@ interface Database<T> {
|
||||
*/
|
||||
Collection<LocalAuthor> getLocalAuthors(T txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all restricted groups to which the user can post messages.
|
||||
* <p>
|
||||
* Locking: identity read.
|
||||
*/
|
||||
Collection<LocalGroup> getLocalGroups(T txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the local transport properties for all transports.
|
||||
* <p>
|
||||
@@ -556,15 +540,6 @@ interface Database<T> {
|
||||
*/
|
||||
Map<GroupId, Integer> getUnreadMessageCounts(T txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the IDs of all messages posted by the given author to
|
||||
* unrestricted groups.
|
||||
* <p>
|
||||
* Locking: message read.
|
||||
*/
|
||||
Collection<MessageId> getUnrestrictedGroupMessages(T txn, AuthorId a)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the contacts to which the given group is visible.
|
||||
* <p>
|
||||
@@ -631,13 +606,6 @@ interface Database<T> {
|
||||
*/
|
||||
void removeContact(T txn, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes the given restricted group to which the user can post messages.
|
||||
* <p>
|
||||
* Locking: identity write.
|
||||
*/
|
||||
void removeLocalGroup(T txn, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a message (and all associated state) from the database.
|
||||
* <p>
|
||||
|
||||
@@ -65,7 +65,6 @@ import net.sf.briar.api.messaging.Ack;
|
||||
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.LocalGroup;
|
||||
import net.sf.briar.api.messaging.Message;
|
||||
import net.sf.briar.api.messaging.MessageId;
|
||||
import net.sf.briar.api.messaging.Offer;
|
||||
@@ -285,22 +284,6 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public void addLocalGroup(LocalGroup g) throws DbException {
|
||||
identityLock.writeLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
db.addLocalGroup(txn, g);
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
identityLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void addLocalGroupMessage(Message m) throws DbException {
|
||||
boolean added = false;
|
||||
contactLock.readLock().lock();
|
||||
@@ -362,13 +345,9 @@ DatabaseCleaner.Callback {
|
||||
if(!c.equals(sender)) db.addStatus(txn, c, id, false);
|
||||
}
|
||||
// Calculate and store the message's sendability
|
||||
if(m.getGroup().isRestricted()) {
|
||||
db.setSendability(txn, id, 1);
|
||||
} else {
|
||||
int sendability = calculateSendability(txn, m);
|
||||
db.setSendability(txn, id, sendability);
|
||||
if(sendability > 0) updateAncestorSendability(txn, id, true);
|
||||
}
|
||||
int sendability = calculateSendability(txn, m);
|
||||
db.setSendability(txn, id, sendability);
|
||||
if(sendability > 0) updateAncestorSendability(txn, id, true);
|
||||
// Count the bytes stored
|
||||
synchronized(spaceLock) {
|
||||
bytesStoredSinceLastCheck += m.getSerialised().length;
|
||||
@@ -1066,23 +1045,6 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<LocalGroup> getLocalGroups() throws DbException {
|
||||
identityLock.readLock().lock();
|
||||
try {
|
||||
T txn = db.startTransaction();
|
||||
try {
|
||||
Collection<LocalGroup> groups = db.getLocalGroups(txn);
|
||||
db.commitTransaction(txn);
|
||||
return groups;
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
identityLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<TransportId, TransportProperties> getLocalProperties()
|
||||
throws DbException {
|
||||
transportLock.readLock().lock();
|
||||
@@ -1964,8 +1926,8 @@ DatabaseCleaner.Callback {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the sendability of all messages posted by the given author to
|
||||
* unrestricted groups, and the ancestors of those messages if necessary.
|
||||
* Updates the sendability of all group messages posted by the given
|
||||
* author, and the ancestors of those messages if necessary.
|
||||
* <p>
|
||||
* Locking: message write.
|
||||
* @param increment true if the user's rating for the author has changed
|
||||
@@ -1973,7 +1935,7 @@ DatabaseCleaner.Callback {
|
||||
*/
|
||||
private void updateAuthorSendability(T txn, AuthorId a, boolean increment)
|
||||
throws DbException {
|
||||
for(MessageId id : db.getUnrestrictedGroupMessages(txn, a)) {
|
||||
for(MessageId id : db.getGroupMessages(txn, a)) {
|
||||
int sendability = db.getSendability(txn, id);
|
||||
if(increment) {
|
||||
db.setSendability(txn, id, sendability + 1);
|
||||
@@ -2125,8 +2087,6 @@ DatabaseCleaner.Callback {
|
||||
throw new NoSuchSubscriptionException();
|
||||
affected = db.getVisibility(txn, id);
|
||||
db.removeSubscription(txn, id);
|
||||
if(db.containsLocalGroup(txn, id))
|
||||
db.removeLocalGroup(txn, id);
|
||||
db.commitTransaction(txn);
|
||||
} catch(DbException e) {
|
||||
db.abortTransaction(txn);
|
||||
|
||||
@@ -43,7 +43,6 @@ import net.sf.briar.api.db.PrivateMessageHeader;
|
||||
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.LocalGroup;
|
||||
import net.sf.briar.api.messaging.Message;
|
||||
import net.sf.briar.api.messaging.MessageId;
|
||||
import net.sf.briar.api.messaging.Rating;
|
||||
@@ -71,15 +70,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
+ " privateKey BINARY NOT NULL,"
|
||||
+ " PRIMARY KEY (authorId))";
|
||||
|
||||
// Locking: identity
|
||||
private static final String CREATE_LOCAL_GROUPS =
|
||||
"CREATE TABLE localGroups"
|
||||
+ " (groupId HASH NOT NULL,"
|
||||
+ " name VARCHAR NOT NULL,"
|
||||
+ " publicKey BINARY NOT NULL,"
|
||||
+ " privateKey BINARY NOT NULL,"
|
||||
+ " PRIMARY KEY (groupId))";
|
||||
|
||||
// Locking: contact
|
||||
// Dependents: message, retention, subscription, transport, window
|
||||
private static final String CREATE_CONTACTS =
|
||||
@@ -104,7 +94,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
"CREATE TABLE groups"
|
||||
+ " (groupId HASH NOT NULL,"
|
||||
+ " name VARCHAR NOT NULL,"
|
||||
+ " publicKey BINARY," // Null for unrestricted groups
|
||||
+ " salt BINARY NOT NULL,"
|
||||
+ " visibleToAll BOOLEAN NOT NULL,"
|
||||
+ " PRIMARY KEY (groupId))";
|
||||
|
||||
@@ -126,7 +116,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
+ " (contactId INT NOT NULL,"
|
||||
+ " groupId HASH NOT NULL," // Not a foreign key
|
||||
+ " name VARCHAR NOT NULL,"
|
||||
+ " publicKey BINARY," // Null for unrestricted groups
|
||||
+ " salt BINARY NOT NULL,"
|
||||
+ " PRIMARY KEY (contactId, groupId),"
|
||||
+ " FOREIGN KEY (contactId)"
|
||||
+ " REFERENCES contacts (contactId)"
|
||||
@@ -406,7 +396,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
try {
|
||||
s = txn.createStatement();
|
||||
s.executeUpdate(insertTypeNames(CREATE_LOCAL_AUTHORS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_LOCAL_GROUPS));
|
||||
s.executeUpdate(insertTypeNames(CREATE_CONTACTS));
|
||||
s.executeUpdate(INDEX_CONTACTS_BY_AUTHOR);
|
||||
s.executeUpdate(insertTypeNames(CREATE_GROUPS));
|
||||
@@ -750,26 +739,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public void addLocalGroup(Connection txn, LocalGroup g) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
String sql = "INSERT INTO localGroups"
|
||||
+ " (groupId, name, publicKey, privateKey)"
|
||||
+ " VALUES (?, ?, ?, ?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, g.getId().getBytes());
|
||||
ps.setString(2, g.getName());
|
||||
ps.setBytes(3, g.getPublicKey());
|
||||
ps.setBytes(4, g.getPrivateKey());
|
||||
int affected = ps.executeUpdate();
|
||||
if(affected != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch(SQLException e) {
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void addMessageToAck(Connection txn, ContactId c, MessageId m)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -916,13 +885,12 @@ 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, visibleToAll)"
|
||||
sql = "INSERT INTO groups (groupId, name, salt, visibleToAll)"
|
||||
+ " VALUES (?, ?, ?, FALSE)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, g.getId().getBytes());
|
||||
ps.setString(2, g.getName());
|
||||
if(g.isRestricted()) ps.setBytes(3, g.getPublicKey());
|
||||
else ps.setNull(3, BINARY);
|
||||
ps.setBytes(3, g.getSalt());
|
||||
int affected = ps.executeUpdate();
|
||||
if(affected != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
@@ -1059,27 +1027,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsLocalGroup(Connection txn, GroupId g)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT NULL FROM localGroups WHERE groupId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, g.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
boolean found = rs.next();
|
||||
if(rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
return found;
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsMessage(Connection txn, MessageId m)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -1172,8 +1119,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
// Add all subscribed groups to the list
|
||||
String sql = "SELECT groupId, name, publicKey, visibleToAll"
|
||||
+ " FROM groups";
|
||||
String sql = "SELECT groupId, name, salt, visibleToAll FROM groups";
|
||||
ps = txn.prepareStatement(sql);
|
||||
rs = ps.executeQuery();
|
||||
List<GroupStatus> groups = new ArrayList<GroupStatus>();
|
||||
@@ -1182,24 +1128,23 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
GroupId id = new GroupId(rs.getBytes(1));
|
||||
subscribed.add(id);
|
||||
String name = rs.getString(2);
|
||||
byte[] publicKey = rs.getBytes(3);
|
||||
Group group = new Group(id, name, publicKey);
|
||||
byte[] salt = rs.getBytes(3);
|
||||
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 contact groups to the list, unless already added
|
||||
sql = "SELECT DISTINCT groupId, name, publicKey"
|
||||
+ " FROM contactGroups";
|
||||
sql = "SELECT DISTINCT groupId, name, salt FROM contactGroups";
|
||||
ps = txn.prepareStatement(sql);
|
||||
rs = ps.executeQuery();
|
||||
while(rs.next()) {
|
||||
GroupId id = new GroupId(rs.getBytes(1));
|
||||
if(subscribed.contains(id)) continue;
|
||||
String name = rs.getString(2);
|
||||
byte[] publicKey = rs.getBytes(3);
|
||||
Group group = new Group(id, name, publicKey);
|
||||
byte[] salt = rs.getBytes(3);
|
||||
Group group = new Group(id, name, salt);
|
||||
groups.add(new GroupStatus(group, false, false));
|
||||
}
|
||||
rs.close();
|
||||
@@ -1340,16 +1285,16 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT name, publicKey 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[] publicKey = rs.getBytes(2);
|
||||
byte[] salt = rs.getBytes(2);
|
||||
rs.close();
|
||||
ps.close();
|
||||
return new Group(g, name, publicKey);
|
||||
return new Group(g, name, salt);
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
@@ -1439,6 +1384,31 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<MessageId> getGroupMessages(Connection txn,
|
||||
AuthorId a) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT messageId"
|
||||
+ " FROM messages AS m"
|
||||
+ " JOIN groups AS g"
|
||||
+ " ON m.groupId = g.groupId"
|
||||
+ " WHERE authorId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, a.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
List<MessageId> ids = new ArrayList<MessageId>();
|
||||
while(rs.next()) ids.add(new MessageId(rs.getBytes(1)));
|
||||
rs.close();
|
||||
ps.close();
|
||||
return Collections.unmodifiableList(ids);
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<ContactId, Long> getLastConnected(Connection txn)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -1512,34 +1482,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<LocalGroup> getLocalGroups(Connection txn)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT groupId, name, publicKey, privateKey"
|
||||
+ " FROM localGroups";
|
||||
ps = txn.prepareStatement(sql);
|
||||
rs = ps.executeQuery();
|
||||
List<LocalGroup> groups = new ArrayList<LocalGroup>();
|
||||
while(rs.next()) {
|
||||
GroupId groupId = new GroupId(rs.getBytes(1));
|
||||
String name = rs.getString(2);
|
||||
byte[] publicKey = rs.getBytes(3);
|
||||
byte[] privateKey = rs.getBytes(4);
|
||||
groups.add(new LocalGroup(groupId, name, publicKey,
|
||||
privateKey));
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
return Collections.unmodifiableList(groups);
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<TransportId, TransportProperties> getLocalProperties(
|
||||
Connection txn) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -2223,7 +2165,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getStarredFlag(Connection txn, MessageId m) throws DbException {
|
||||
public boolean getStarredFlag(Connection txn, MessageId m)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
@@ -2249,15 +2192,15 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT groupId, name, publicKey FROM groups";
|
||||
String sql = "SELECT groupId, name, salt FROM groups";
|
||||
ps = txn.prepareStatement(sql);
|
||||
rs = ps.executeQuery();
|
||||
List<Group> subs = new ArrayList<Group>();
|
||||
while(rs.next()) {
|
||||
GroupId groupId = new GroupId(rs.getBytes(1));
|
||||
String name = rs.getString(2);
|
||||
byte[] publicKey = rs.getBytes(3);
|
||||
subs.add(new Group(groupId, name, publicKey));
|
||||
byte[] salt = rs.getBytes(3);
|
||||
subs.add(new Group(groupId, name, salt));
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
@@ -2274,7 +2217,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT groupId, name, publicKey FROM contactGroups"
|
||||
String sql = "SELECT groupId, name, salt FROM contactGroups"
|
||||
+ " WHERE contactId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
@@ -2283,8 +2226,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
while(rs.next()) {
|
||||
GroupId groupId = new GroupId(rs.getBytes(1));
|
||||
String name = rs.getString(2);
|
||||
byte[] publicKey = rs.getBytes(3);
|
||||
subs.add(new Group(groupId, name, publicKey));
|
||||
byte[] salt = rs.getBytes(3);
|
||||
subs.add(new Group(groupId, name, salt));
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
@@ -2336,7 +2279,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT g.groupId, name, publicKey,"
|
||||
String sql = "SELECT g.groupId, name, salt,"
|
||||
+ " localVersion, txCount"
|
||||
+ " FROM groups AS g"
|
||||
+ " JOIN groupVisibilities AS vis"
|
||||
@@ -2356,8 +2299,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
while(rs.next()) {
|
||||
GroupId groupId = new GroupId(rs.getBytes(1));
|
||||
String name = rs.getString(2);
|
||||
byte[] key = rs.getBytes(3);
|
||||
subs.add(new Group(groupId, name, key));
|
||||
byte[] salt = rs.getBytes(3);
|
||||
subs.add(new Group(groupId, name, salt));
|
||||
version = rs.getLong(4);
|
||||
txCount = rs.getInt(5);
|
||||
}
|
||||
@@ -2564,32 +2507,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<MessageId> getUnrestrictedGroupMessages(Connection txn,
|
||||
AuthorId a) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT messageId"
|
||||
+ " FROM messages AS m"
|
||||
+ " JOIN groups AS g"
|
||||
+ " ON m.groupId = g.groupId"
|
||||
+ " WHERE authorId = ?"
|
||||
+ " AND publicKey IS NULL";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, a.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
List<MessageId> ids = new ArrayList<MessageId>();
|
||||
while(rs.next()) ids.add(new MessageId(rs.getBytes(1)));
|
||||
rs.close();
|
||||
ps.close();
|
||||
return Collections.unmodifiableList(ids);
|
||||
} catch(SQLException e) {
|
||||
tryToClose(rs);
|
||||
tryToClose(ps);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<ContactId> getVisibility(Connection txn, GroupId g)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -2808,21 +2725,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
public void removeLocalGroup(Connection txn, GroupId g) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
String sql = "DELETE FROM localGroups WHERE groupId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, 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 removeMessage(Connection txn, MessageId m) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
@@ -3395,15 +3297,14 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
// Store the new subscriptions, if any
|
||||
if(subs.isEmpty()) return true;
|
||||
sql = "INSERT INTO contactGroups"
|
||||
+ " (contactId, groupId, name, publicKey)"
|
||||
+ " (contactId, groupId, name, salt)"
|
||||
+ " VALUES (?, ?, ?, ?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
for(Group g : subs) {
|
||||
ps.setBytes(2, g.getId().getBytes());
|
||||
ps.setString(3, g.getName());
|
||||
if(g.isRestricted()) ps.setBytes(4, g.getPublicKey());
|
||||
else ps.setNull(4, BINARY);
|
||||
ps.setBytes(4, g.getSalt());
|
||||
ps.addBatch();
|
||||
}
|
||||
int[] batchAffected = ps.executeBatch();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.sf.briar.messaging;
|
||||
|
||||
import static net.sf.briar.api.messaging.MessagingConstants.GROUP_SALT_LENGTH;
|
||||
import static net.sf.briar.api.messaging.Types.GROUP;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -10,7 +11,6 @@ import net.sf.briar.api.crypto.MessageDigest;
|
||||
import net.sf.briar.api.messaging.Group;
|
||||
import net.sf.briar.api.messaging.GroupFactory;
|
||||
import net.sf.briar.api.messaging.GroupId;
|
||||
import net.sf.briar.api.messaging.LocalGroup;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
|
||||
@@ -28,29 +28,20 @@ class GroupFactoryImpl implements GroupFactory {
|
||||
}
|
||||
|
||||
public Group createGroup(String name) throws IOException {
|
||||
return createGroup(name, null);
|
||||
byte[] salt = new byte[GROUP_SALT_LENGTH];
|
||||
crypto.getSecureRandom().nextBytes(salt);
|
||||
return createGroup(name, salt);
|
||||
}
|
||||
|
||||
public Group createGroup(String name, byte[] publicKey) throws IOException {
|
||||
GroupId id = getId(name, publicKey);
|
||||
return new Group(id, name, publicKey);
|
||||
}
|
||||
|
||||
public LocalGroup createLocalGroup(String name, byte[] publicKey,
|
||||
byte[] privateKey) throws IOException {
|
||||
GroupId id = getId(name, publicKey);
|
||||
return new LocalGroup(id, name, publicKey, privateKey);
|
||||
}
|
||||
|
||||
private GroupId getId(String name, byte[] publicKey) throws IOException {
|
||||
public Group createGroup(String name, byte[] salt) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
Writer w = writerFactory.createWriter(out);
|
||||
w.writeStructId(GROUP);
|
||||
w.writeString(name);
|
||||
if(publicKey == null) w.writeNull();
|
||||
else w.writeBytes(publicKey);
|
||||
w.writeBytes(salt);
|
||||
MessageDigest messageDigest = crypto.getMessageDigest();
|
||||
messageDigest.update(out.toByteArray());
|
||||
return new GroupId(messageDigest.digest());
|
||||
GroupId id = new GroupId(messageDigest.digest());
|
||||
return new Group(id, name, salt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import static net.sf.briar.api.messaging.MessagingConstants.MAX_BODY_LENGTH;
|
||||
import static net.sf.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
|
||||
import static net.sf.briar.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
||||
import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBJECT_LENGTH;
|
||||
import static net.sf.briar.api.messaging.MessagingConstants.SALT_LENGTH;
|
||||
import static net.sf.briar.api.messaging.MessagingConstants.MESSAGE_SALT_LENGTH;
|
||||
import static net.sf.briar.api.messaging.Types.AUTHOR;
|
||||
import static net.sf.briar.api.messaging.Types.GROUP;
|
||||
import static net.sf.briar.api.messaging.Types.MESSAGE;
|
||||
@@ -39,7 +39,7 @@ import com.google.inject.Inject;
|
||||
|
||||
class MessageFactoryImpl implements MessageFactory {
|
||||
|
||||
private final Signature authorSignature, groupSignature;
|
||||
private final Signature signature;
|
||||
private final SecureRandom random;
|
||||
private final MessageDigest messageDigest;
|
||||
private final WriterFactory writerFactory;
|
||||
@@ -49,8 +49,7 @@ class MessageFactoryImpl implements MessageFactory {
|
||||
@Inject
|
||||
MessageFactoryImpl(CryptoComponent crypto, WriterFactory writerFactory,
|
||||
Clock clock) {
|
||||
authorSignature = crypto.getSignature();
|
||||
groupSignature = crypto.getSignature();
|
||||
signature = crypto.getSignature();
|
||||
random = crypto.getSecureRandom();
|
||||
messageDigest = crypto.getMessageDigest();
|
||||
this.writerFactory = writerFactory;
|
||||
@@ -60,46 +59,27 @@ class MessageFactoryImpl implements MessageFactory {
|
||||
|
||||
public Message createPrivateMessage(MessageId parent, String contentType,
|
||||
byte[] body) throws IOException, GeneralSecurityException {
|
||||
return createMessage(parent, null, null, null, null, contentType, body);
|
||||
return createMessage(parent, null, null, null, contentType, body);
|
||||
}
|
||||
|
||||
public Message createAnonymousMessage(MessageId parent, Group group,
|
||||
String contentType, byte[] body) throws IOException,
|
||||
GeneralSecurityException {
|
||||
return createMessage(parent, group, null, null, null, contentType,
|
||||
body);
|
||||
}
|
||||
|
||||
public Message createAnonymousMessage(MessageId parent, Group group,
|
||||
PrivateKey groupKey, String contentType, byte[] body)
|
||||
throws IOException, GeneralSecurityException {
|
||||
return createMessage(parent, group, groupKey, null, null, contentType,
|
||||
body);
|
||||
return createMessage(parent, group, null, null, contentType, body);
|
||||
}
|
||||
|
||||
public Message createPseudonymousMessage(MessageId parent, Group group,
|
||||
Author author, PrivateKey authorKey, String contentType,
|
||||
Author author, PrivateKey privateKey, String contentType,
|
||||
byte[] body) throws IOException, GeneralSecurityException {
|
||||
return createMessage(parent, group, null, author, authorKey,
|
||||
contentType, body);
|
||||
return createMessage(parent, group, author, privateKey, contentType,
|
||||
body);
|
||||
}
|
||||
|
||||
public Message createPseudonymousMessage(MessageId parent, Group group,
|
||||
PrivateKey groupKey, Author author, PrivateKey authorKey,
|
||||
String contentType, byte[] body) throws IOException,
|
||||
GeneralSecurityException {
|
||||
return createMessage(parent, group, groupKey, author, authorKey,
|
||||
contentType, body);
|
||||
}
|
||||
|
||||
private Message createMessage(MessageId parent, Group group,
|
||||
PrivateKey groupKey, Author author, PrivateKey authorKey,
|
||||
String contentType, byte[] body) throws IOException,
|
||||
GeneralSecurityException {
|
||||
private Message createMessage(MessageId parent, Group group, Author author,
|
||||
PrivateKey privateKey, String contentType, byte[] body)
|
||||
throws IOException, GeneralSecurityException {
|
||||
// Validate the arguments
|
||||
if((author == null) != (authorKey == null))
|
||||
throw new IllegalArgumentException();
|
||||
if((group == null || !group.isRestricted()) != (groupKey == null))
|
||||
if((author == null) != (privateKey == null))
|
||||
throw new IllegalArgumentException();
|
||||
if(contentType.getBytes("UTF-8").length > MAX_CONTENT_TYPE_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
@@ -113,17 +93,11 @@ class MessageFactoryImpl implements MessageFactory {
|
||||
w.addConsumer(counting);
|
||||
Consumer digestingConsumer = new DigestingConsumer(messageDigest);
|
||||
w.addConsumer(digestingConsumer);
|
||||
Consumer authorConsumer = null;
|
||||
if(authorKey != null) {
|
||||
authorSignature.initSign(authorKey);
|
||||
authorConsumer = new SigningConsumer(authorSignature);
|
||||
w.addConsumer(authorConsumer);
|
||||
}
|
||||
Consumer groupConsumer = null;
|
||||
if(groupKey != null) {
|
||||
groupSignature.initSign(groupKey);
|
||||
groupConsumer = new SigningConsumer(groupSignature);
|
||||
w.addConsumer(groupConsumer);
|
||||
Consumer signingConsumer = null;
|
||||
if(privateKey != null) {
|
||||
signature.initSign(privateKey);
|
||||
signingConsumer = new SigningConsumer(signature);
|
||||
w.addConsumer(signingConsumer);
|
||||
}
|
||||
// Write the message
|
||||
w.writeStructId(MESSAGE);
|
||||
@@ -136,32 +110,22 @@ class MessageFactoryImpl implements MessageFactory {
|
||||
w.writeString(contentType);
|
||||
long timestamp = clock.currentTimeMillis();
|
||||
w.writeInt64(timestamp);
|
||||
byte[] salt = new byte[SALT_LENGTH];
|
||||
byte[] salt = new byte[MESSAGE_SALT_LENGTH];
|
||||
random.nextBytes(salt);
|
||||
w.writeBytes(salt);
|
||||
w.writeBytes(body);
|
||||
int bodyStart = (int) counting.getCount() - body.length;
|
||||
// Sign the message with the author's private key, if there is one
|
||||
if(authorKey == null) {
|
||||
if(privateKey == null) {
|
||||
w.writeNull();
|
||||
} else {
|
||||
w.removeConsumer(authorConsumer);
|
||||
byte[] sig = authorSignature.sign();
|
||||
w.removeConsumer(signingConsumer);
|
||||
byte[] sig = signature.sign();
|
||||
if(sig.length > MAX_SIGNATURE_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
w.writeBytes(sig);
|
||||
}
|
||||
// Sign the message with the group's private key, if there is one
|
||||
if(groupKey == null) {
|
||||
w.writeNull();
|
||||
} else {
|
||||
w.removeConsumer(groupConsumer);
|
||||
byte[] sig = groupSignature.sign();
|
||||
if(sig.length > MAX_SIGNATURE_LENGTH)
|
||||
throw new IllegalArgumentException();
|
||||
w.writeBytes(sig);
|
||||
}
|
||||
// Hash the message, including the signatures, to get the message ID
|
||||
// Hash the message, including the signature, to get the message ID
|
||||
w.removeConsumer(digestingConsumer);
|
||||
MessageId id = new MessageId(messageDigest.digest());
|
||||
// If the content type is text/plain, extract a subject line
|
||||
@@ -181,8 +145,7 @@ class MessageFactoryImpl implements MessageFactory {
|
||||
private void writeGroup(Writer w, Group g) throws IOException {
|
||||
w.writeStructId(GROUP);
|
||||
w.writeString(g.getName());
|
||||
if(g.isRestricted()) w.writeBytes(g.getPublicKey());
|
||||
else w.writeNull();
|
||||
w.writeBytes(g.getSalt());
|
||||
}
|
||||
|
||||
private void writeAuthor(Writer w, Author a) throws IOException {
|
||||
|
||||
@@ -5,7 +5,7 @@ import static net.sf.briar.api.messaging.MessagingConstants.MAX_BODY_LENGTH;
|
||||
import static net.sf.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
|
||||
import static net.sf.briar.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
||||
import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBJECT_LENGTH;
|
||||
import static net.sf.briar.api.messaging.MessagingConstants.SALT_LENGTH;
|
||||
import static net.sf.briar.api.messaging.MessagingConstants.MESSAGE_SALT_LENGTH;
|
||||
import static net.sf.briar.api.messaging.Types.MESSAGE;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -67,8 +67,8 @@ class MessageReader implements StructReader<UnverifiedMessage> {
|
||||
long timestamp = r.readInt64();
|
||||
if(timestamp < 0) throw new FormatException();
|
||||
// Read the salt
|
||||
byte[] salt = r.readBytes(SALT_LENGTH);
|
||||
if(salt.length < SALT_LENGTH) throw new FormatException();
|
||||
byte[] salt = r.readBytes(MESSAGE_SALT_LENGTH);
|
||||
if(salt.length < MESSAGE_SALT_LENGTH) throw new FormatException();
|
||||
// Read the message body
|
||||
byte[] body = r.readBytes(MAX_BODY_LENGTH);
|
||||
// If the content type is text/plain, extract a subject line
|
||||
@@ -84,23 +84,17 @@ class MessageReader implements StructReader<UnverifiedMessage> {
|
||||
// Record the offset of the body within the message
|
||||
int bodyStart = (int) counting.getCount() - body.length;
|
||||
// Record the length of the data covered by the author's signature
|
||||
int signedByAuthor = (int) counting.getCount();
|
||||
int signedLength = (int) counting.getCount();
|
||||
// Read the author's signature, if there is one
|
||||
byte[] authorSig = null;
|
||||
byte[] signature = null;
|
||||
if(author == null) r.readNull();
|
||||
else authorSig = r.readBytes(MAX_SIGNATURE_LENGTH);
|
||||
// Record the length of the data covered by the group's signature
|
||||
int signedByGroup = (int) counting.getCount();
|
||||
// Read the group's signature, if there is one
|
||||
byte[] groupSig = null;
|
||||
if(group == null || !group.isRestricted()) r.readNull();
|
||||
else groupSig = r.readBytes(MAX_SIGNATURE_LENGTH);
|
||||
// That's all, folks
|
||||
else signature = r.readBytes(MAX_SIGNATURE_LENGTH);
|
||||
// The signature will be verified later
|
||||
r.removeConsumer(counting);
|
||||
r.removeConsumer(copying);
|
||||
byte[] raw = copying.getCopy();
|
||||
return new UnverifiedMessage(parent, group, author, contentType,
|
||||
subject, timestamp, raw, authorSig, groupSig, bodyStart,
|
||||
body.length, signedByAuthor, signedByGroup);
|
||||
subject, timestamp, raw, signature, bodyStart, body.length,
|
||||
signedLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import net.sf.briar.api.crypto.KeyParser;
|
||||
import net.sf.briar.api.crypto.MessageDigest;
|
||||
import net.sf.briar.api.crypto.PublicKey;
|
||||
import net.sf.briar.api.crypto.Signature;
|
||||
import net.sf.briar.api.messaging.Group;
|
||||
import net.sf.briar.api.messaging.Message;
|
||||
import net.sf.briar.api.messaging.MessageId;
|
||||
import net.sf.briar.api.messaging.MessageVerifier;
|
||||
@@ -31,7 +30,7 @@ class MessageVerifierImpl implements MessageVerifier {
|
||||
throws GeneralSecurityException {
|
||||
MessageDigest messageDigest = crypto.getMessageDigest();
|
||||
Signature signature = crypto.getSignature();
|
||||
// Hash the message, including the signatures, to get the message ID
|
||||
// Hash the message, including the signature, to get the message ID
|
||||
byte[] raw = m.getSerialised();
|
||||
messageDigest.update(raw);
|
||||
MessageId id = new MessageId(messageDigest.digest());
|
||||
@@ -40,20 +39,11 @@ class MessageVerifierImpl implements MessageVerifier {
|
||||
if(author != null) {
|
||||
PublicKey k = keyParser.parsePublicKey(author.getPublicKey());
|
||||
signature.initVerify(k);
|
||||
signature.update(raw, 0, m.getLengthSignedByAuthor());
|
||||
if(!signature.verify(m.getAuthorSignature()))
|
||||
signature.update(raw, 0, m.getSignedLength());
|
||||
if(!signature.verify(m.getSignature()))
|
||||
throw new GeneralSecurityException();
|
||||
}
|
||||
// Verify the group's signature, if there is one
|
||||
Group group = m.getGroup();
|
||||
if(group != null && group.isRestricted()) {
|
||||
PublicKey k = keyParser.parsePublicKey(group.getPublicKey());
|
||||
signature.initVerify(k);
|
||||
signature.update(raw, 0, m.getLengthSignedByGroup());
|
||||
if(!signature.verify(m.getGroupSignature()))
|
||||
throw new GeneralSecurityException();
|
||||
}
|
||||
return new MessageImpl(id, m.getParent(), group, author,
|
||||
return new MessageImpl(id, m.getParent(), m.getGroup(), author,
|
||||
m.getContentType(), m.getSubject(), m.getTimestamp(), raw,
|
||||
m.getBodyStart(), m.getBodyLength());
|
||||
}
|
||||
|
||||
@@ -133,8 +133,7 @@ class PacketWriterImpl implements PacketWriter {
|
||||
for(Group g : u.getGroups()) {
|
||||
w.writeStructId(GROUP);
|
||||
w.writeString(g.getName());
|
||||
if(g.isRestricted()) w.writeBytes(g.getPublicKey());
|
||||
else w.writeNull();
|
||||
w.writeBytes(g.getSalt());
|
||||
}
|
||||
w.writeListEnd();
|
||||
w.writeInt64(u.getVersion());
|
||||
|
||||
Reference in New Issue
Block a user