mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 20:29:52 +01:00
Move handshake keys from LocalAuthor to Account.
This commit is contained in:
@@ -4,8 +4,8 @@ import org.briarproject.bramble.api.account.AccountManager;
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.api.identity.Account;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.bramble.util.IoUtils;
|
||||
@@ -161,8 +161,8 @@ class AccountManagerImpl implements AccountManager {
|
||||
synchronized (stateChangeLock) {
|
||||
if (hasDatabaseKey())
|
||||
throw new AssertionError("Already have a database key");
|
||||
LocalAuthor localAuthor = identityManager.createLocalAuthor(name);
|
||||
identityManager.registerLocalAuthor(localAuthor);
|
||||
Account account = identityManager.createAccount(name);
|
||||
identityManager.registerAccount(account);
|
||||
SecretKey key = crypto.generateSecretKey();
|
||||
if (!encryptAndStoreDatabaseKey(key, password)) return false;
|
||||
databaseKey = key;
|
||||
|
||||
@@ -13,9 +13,9 @@ import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.MessageDeletedException;
|
||||
import org.briarproject.bramble.api.db.Metadata;
|
||||
import org.briarproject.bramble.api.db.MigrationListener;
|
||||
import org.briarproject.bramble.api.identity.Account;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.settings.Settings;
|
||||
@@ -86,6 +86,11 @@ interface Database<T> {
|
||||
*/
|
||||
void commitTransaction(T txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores an account.
|
||||
*/
|
||||
void addAccount(T txn, Account a) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a contact associated with the given local and remote pseudonyms,
|
||||
* and returns an ID for the contact.
|
||||
@@ -119,11 +124,6 @@ interface Database<T> {
|
||||
HandshakeKeySetId addHandshakeKeys(T txn, PendingContactId p,
|
||||
HandshakeKeys k) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a local pseudonym.
|
||||
*/
|
||||
void addLocalAuthor(T txn, LocalAuthor a) throws DbException;
|
||||
|
||||
/**
|
||||
* Stores a message.
|
||||
*
|
||||
@@ -163,6 +163,13 @@ interface Database<T> {
|
||||
TransportKeySetId addTransportKeys(T txn, ContactId c, TransportKeys k)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains an account for the given pseudonym.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
boolean containsAccount(T txn, AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given contact for the given
|
||||
* local pseudonym.
|
||||
@@ -186,13 +193,6 @@ interface Database<T> {
|
||||
*/
|
||||
boolean containsGroup(T txn, GroupId g) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given local pseudonym.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
boolean containsLocalAuthor(T txn, AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given message.
|
||||
* <p/>
|
||||
@@ -245,6 +245,20 @@ interface Database<T> {
|
||||
*/
|
||||
void deleteMessageMetadata(T txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the account for local pseudonym with the given ID.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Account getAccount(T txn, AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the accounts for all local pseudonyms.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Collection<Account> getAccounts(T txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the contact with the given ID.
|
||||
* <p/>
|
||||
@@ -322,20 +336,6 @@ interface Database<T> {
|
||||
Collection<HandshakeKeySet> getHandshakeKeys(T txn, TransportId t)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the local pseudonym with the given ID.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
LocalAuthor getLocalAuthor(T txn, AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns all local pseudonyms.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
Collection<LocalAuthor> getLocalAuthors(T txn) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the message with the given ID.
|
||||
* <p/>
|
||||
@@ -605,6 +605,11 @@ interface Database<T> {
|
||||
*/
|
||||
void raiseSeenFlag(T txn, ContactId c, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes an account (and all associated state) from the database.
|
||||
*/
|
||||
void removeAccount(T txn, AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a contact from the database.
|
||||
*/
|
||||
@@ -628,11 +633,6 @@ interface Database<T> {
|
||||
void removeHandshakeKeys(T txn, TransportId t, HandshakeKeySetId k)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a local pseudonym (and all associated state) from the database.
|
||||
*/
|
||||
void removeLocalAuthor(T txn, AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Removes a message (and all associated state) from the database.
|
||||
*/
|
||||
@@ -686,7 +686,7 @@ interface Database<T> {
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the handshake key pair for the local pseudonym with the given ID.
|
||||
* Sets the handshake key pair for the account with the given ID.
|
||||
*/
|
||||
void setHandshakeKeyPair(T txn, AuthorId local, byte[] publicKey,
|
||||
byte[] privateKey) throws DbException;
|
||||
|
||||
@@ -30,9 +30,9 @@ import org.briarproject.bramble.api.db.TaskAction;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.event.EventExecutor;
|
||||
import org.briarproject.bramble.api.identity.Account;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.identity.event.LocalAuthorAddedEvent;
|
||||
import org.briarproject.bramble.api.identity.event.LocalAuthorRemovedEvent;
|
||||
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
|
||||
@@ -231,15 +231,26 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
return txnClass.cast(transaction.unbox());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAccount(Transaction transaction, Account a)
|
||||
throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsAccount(txn, a.getId())) {
|
||||
db.addAccount(txn, a);
|
||||
transaction.attach(new LocalAuthorAddedEvent(a.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactId addContact(Transaction transaction, Author remote,
|
||||
AuthorId local, boolean verified)
|
||||
throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsLocalAuthor(txn, local))
|
||||
if (!db.containsAccount(txn, local))
|
||||
throw new NoSuchLocalAuthorException();
|
||||
if (db.containsLocalAuthor(txn, remote.getId()))
|
||||
if (db.containsAccount(txn, remote.getId()))
|
||||
throw new ContactExistsException();
|
||||
if (db.containsContact(txn, remote.getId(), local))
|
||||
throw new ContactExistsException();
|
||||
@@ -282,17 +293,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
return db.addHandshakeKeys(txn, p, k);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLocalAuthor(Transaction transaction, LocalAuthor a)
|
||||
throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsLocalAuthor(txn, a.getId())) {
|
||||
db.addLocalAuthor(txn, a);
|
||||
transaction.attach(new LocalAuthorAddedEvent(a.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLocalMessage(Transaction transaction, Message m,
|
||||
Metadata meta, boolean shared) throws DbException {
|
||||
@@ -341,11 +341,18 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
return db.addTransportKeys(txn, c, k);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAccount(Transaction transaction, AuthorId local)
|
||||
throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
return db.containsAccount(txn, local);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsContact(Transaction transaction, AuthorId remote,
|
||||
AuthorId local) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsLocalAuthor(txn, local))
|
||||
if (!db.containsAccount(txn, local))
|
||||
throw new NoSuchLocalAuthorException();
|
||||
return db.containsContact(txn, remote, local);
|
||||
}
|
||||
@@ -357,13 +364,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
return db.containsGroup(txn, g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsLocalAuthor(Transaction transaction, AuthorId local)
|
||||
throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
return db.containsLocalAuthor(txn, local);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPendingContact(Transaction transaction,
|
||||
PendingContactId p) throws DbException {
|
||||
@@ -478,6 +478,22 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
return messages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account getAccount(Transaction transaction, AuthorId a)
|
||||
throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsAccount(txn, a))
|
||||
throw new NoSuchLocalAuthorException();
|
||||
return db.getAccount(txn, a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Account> getAccounts(Transaction transaction)
|
||||
throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
return db.getAccounts(txn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Contact getContact(Transaction transaction, ContactId c)
|
||||
throws DbException {
|
||||
@@ -505,7 +521,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
public Collection<ContactId> getContacts(Transaction transaction,
|
||||
AuthorId a) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsLocalAuthor(txn, a))
|
||||
if (!db.containsAccount(txn, a))
|
||||
throw new NoSuchLocalAuthorException();
|
||||
return db.getContacts(txn, a);
|
||||
}
|
||||
@@ -553,22 +569,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
return db.getHandshakeKeys(txn, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalAuthor getLocalAuthor(Transaction transaction, AuthorId a)
|
||||
throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsLocalAuthor(txn, a))
|
||||
throw new NoSuchLocalAuthorException();
|
||||
return db.getLocalAuthor(txn, a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LocalAuthor> getLocalAuthors(Transaction transaction)
|
||||
throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
return db.getLocalAuthors(txn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message getMessage(Transaction transaction, MessageId m)
|
||||
throws DbException {
|
||||
@@ -868,6 +868,17 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
if (requested) transaction.attach(new MessageRequestedEvent(c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAccount(Transaction transaction, AuthorId a)
|
||||
throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsAccount(txn, a))
|
||||
throw new NoSuchLocalAuthorException();
|
||||
db.removeAccount(txn, a);
|
||||
transaction.attach(new LocalAuthorRemovedEvent(a));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeContact(Transaction transaction, ContactId c)
|
||||
throws DbException {
|
||||
@@ -904,17 +915,6 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
db.removeHandshakeKeys(txn, t, k);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLocalAuthor(Transaction transaction, AuthorId a)
|
||||
throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsLocalAuthor(txn, a))
|
||||
throw new NoSuchLocalAuthorException();
|
||||
db.removeLocalAuthor(txn, a);
|
||||
transaction.attach(new LocalAuthorRemovedEvent(a));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessage(Transaction transaction, MessageId m)
|
||||
throws DbException {
|
||||
@@ -1040,7 +1040,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
byte[] publicKey, byte[] privateKey) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsLocalAuthor(txn, local))
|
||||
if (!db.containsAccount(txn, local))
|
||||
throw new NoSuchLocalAuthorException();
|
||||
db.setHandshakeKeyPair(txn, local, publicKey, privateKey);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.MessageDeletedException;
|
||||
import org.briarproject.bramble.api.db.Metadata;
|
||||
import org.briarproject.bramble.api.db.MigrationListener;
|
||||
import org.briarproject.bramble.api.identity.Account;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
@@ -661,6 +662,35 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
if (interrupted) Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAccount(Connection txn, Account a) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
String sql = "INSERT INTO localAuthors"
|
||||
+ " (authorId, formatVersion, name, publicKey, privateKey,"
|
||||
+ " handshakePublicKey, handshakePrivateKey, created)"
|
||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
LocalAuthor local = a.getLocalAuthor();
|
||||
ps.setBytes(1, local.getId().getBytes());
|
||||
ps.setInt(2, local.getFormatVersion());
|
||||
ps.setString(3, local.getName());
|
||||
ps.setBytes(4, local.getPublicKey());
|
||||
ps.setBytes(5, local.getPrivateKey());
|
||||
if (a.getHandshakePublicKey() == null) ps.setNull(6, BINARY);
|
||||
else ps.setBytes(6, a.getHandshakePublicKey());
|
||||
if (a.getHandshakePrivateKey() == null) ps.setNull(7, BINARY);
|
||||
else ps.setBytes(7, a.getHandshakePrivateKey());
|
||||
ps.setLong(8, a.getTimeCreated());
|
||||
int affected = ps.executeUpdate();
|
||||
if (affected != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactId addContact(Connection txn, Author remote, AuthorId local,
|
||||
boolean verified) throws DbException {
|
||||
@@ -873,35 +903,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLocalAuthor(Connection txn, LocalAuthor a)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
String sql = "INSERT INTO localAuthors"
|
||||
+ " (authorId, formatVersion, name, publicKey, privateKey,"
|
||||
+ " handshakePublicKey, handshakePrivateKey, created)"
|
||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, a.getId().getBytes());
|
||||
ps.setInt(2, a.getFormatVersion());
|
||||
ps.setString(3, a.getName());
|
||||
ps.setBytes(4, a.getPublicKey());
|
||||
ps.setBytes(5, a.getPrivateKey());
|
||||
if (a.getHandshakePublicKey() == null) ps.setNull(6, BINARY);
|
||||
else ps.setBytes(6, a.getHandshakePublicKey());
|
||||
if (a.getHandshakePrivateKey() == null) ps.setNull(7, BINARY);
|
||||
else ps.setBytes(7, a.getHandshakePrivateKey());
|
||||
ps.setLong(8, a.getTimeCreated());
|
||||
int affected = ps.executeUpdate();
|
||||
if (affected != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMessage(Connection txn, Message m, MessageState state,
|
||||
boolean messageShared, @Nullable ContactId sender)
|
||||
@@ -1179,6 +1180,28 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAccount(Connection txn, AuthorId a)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT NULL FROM localAuthors WHERE authorId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, a.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, LOG, WARNING);
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsContact(Connection txn, AuthorId remote,
|
||||
AuthorId local) throws DbException {
|
||||
@@ -1247,28 +1270,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsLocalAuthor(Connection txn, AuthorId a)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT NULL FROM localAuthors WHERE authorId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, a.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, LOG, WARNING);
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsMessage(Connection txn, MessageId m)
|
||||
throws DbException {
|
||||
@@ -1426,6 +1427,76 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account getAccount(Connection txn, AuthorId a) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT formatVersion, name, publicKey, privateKey,"
|
||||
+ " handshakePublicKey, handshakePrivateKey, created"
|
||||
+ " FROM localAuthors"
|
||||
+ " WHERE authorId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, a.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
if (!rs.next()) throw new DbStateException();
|
||||
int formatVersion = rs.getInt(1);
|
||||
String name = rs.getString(2);
|
||||
byte[] publicKey = rs.getBytes(3);
|
||||
byte[] privateKey = rs.getBytes(4);
|
||||
byte[] handshakePublicKey = rs.getBytes(5);
|
||||
byte[] handshakePrivateKey = rs.getBytes(6);
|
||||
long created = rs.getLong(7);
|
||||
if (rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
LocalAuthor local = new LocalAuthor(a, formatVersion, name,
|
||||
publicKey, privateKey);
|
||||
return new Account(local, handshakePublicKey, handshakePrivateKey,
|
||||
created);
|
||||
} catch (SQLException e) {
|
||||
tryToClose(rs, LOG, WARNING);
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Account> getAccounts(Connection txn) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT authorId, formatVersion, name, publicKey,"
|
||||
+ " privateKey, handshakePublicKey, handshakePrivateKey,"
|
||||
+ " created"
|
||||
+ " FROM localAuthors";
|
||||
ps = txn.prepareStatement(sql);
|
||||
rs = ps.executeQuery();
|
||||
List<Account> accounts = new ArrayList<>();
|
||||
while (rs.next()) {
|
||||
AuthorId authorId = new AuthorId(rs.getBytes(1));
|
||||
int formatVersion = rs.getInt(2);
|
||||
String name = rs.getString(3);
|
||||
byte[] publicKey = rs.getBytes(4);
|
||||
byte[] privateKey = rs.getBytes(5);
|
||||
byte[] handshakePublicKey = rs.getBytes(6);
|
||||
byte[] handshakePrivateKey = rs.getBytes(7);
|
||||
long created = rs.getLong(8);
|
||||
LocalAuthor local = new LocalAuthor(authorId, formatVersion,
|
||||
name, publicKey, privateKey);
|
||||
accounts.add(new Account(local, handshakePublicKey,
|
||||
handshakePrivateKey, created));
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
return accounts;
|
||||
} catch (SQLException e) {
|
||||
tryToClose(rs, LOG, WARNING);
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Contact getContact(Connection txn, ContactId c) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -1660,49 +1731,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalAuthor getLocalAuthor(Connection txn, AuthorId a)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT formatVersion, name, publicKey, privateKey,"
|
||||
+ " handshakePublicKey, handshakePrivateKey, created"
|
||||
+ " FROM localAuthors"
|
||||
+ " WHERE authorId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, a.getBytes());
|
||||
rs = ps.executeQuery();
|
||||
if (!rs.next()) throw new DbStateException();
|
||||
int formatVersion = rs.getInt(1);
|
||||
String name = rs.getString(2);
|
||||
byte[] publicKey = rs.getBytes(3);
|
||||
byte[] privateKey = rs.getBytes(4);
|
||||
byte[] handshakePublicKey = rs.getBytes(5);
|
||||
byte[] handshakePrivateKey = rs.getBytes(6);
|
||||
long created = rs.getLong(7);
|
||||
if (rs.next()) throw new DbStateException();
|
||||
LocalAuthor localAuthor;
|
||||
if (handshakePublicKey == null) {
|
||||
if (handshakePrivateKey != null) throw new DbStateException();
|
||||
localAuthor = new LocalAuthor(a, formatVersion, name,
|
||||
publicKey, privateKey, created);
|
||||
} else {
|
||||
if (handshakePrivateKey == null) throw new DbStateException();
|
||||
localAuthor = new LocalAuthor(a, formatVersion, name,
|
||||
publicKey, privateKey, handshakePublicKey,
|
||||
handshakePrivateKey, created);
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
return localAuthor;
|
||||
} catch (SQLException e) {
|
||||
tryToClose(rs, LOG, WARNING);
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<HandshakeKeySet> getHandshakeKeys(Connection txn,
|
||||
TransportId t) throws DbException {
|
||||
@@ -1783,42 +1811,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LocalAuthor> getLocalAuthors(Connection txn)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT authorId, formatVersion, name, publicKey,"
|
||||
+ " privateKey, handshakePublicKey, handshakePrivateKey,"
|
||||
+ " created"
|
||||
+ " FROM localAuthors";
|
||||
ps = txn.prepareStatement(sql);
|
||||
rs = ps.executeQuery();
|
||||
List<LocalAuthor> authors = new ArrayList<>();
|
||||
while (rs.next()) {
|
||||
AuthorId authorId = new AuthorId(rs.getBytes(1));
|
||||
int formatVersion = rs.getInt(2);
|
||||
String name = rs.getString(3);
|
||||
byte[] publicKey = rs.getBytes(4);
|
||||
byte[] privateKey = rs.getBytes(5);
|
||||
byte[] handshakePublicKey = rs.getBytes(6);
|
||||
byte[] handshakePrivateKey = rs.getBytes(7);
|
||||
long created = rs.getLong(8);
|
||||
authors.add(new LocalAuthor(authorId, formatVersion, name,
|
||||
publicKey, privateKey, handshakePublicKey,
|
||||
handshakePrivateKey, created));
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
return authors;
|
||||
} catch (SQLException e) {
|
||||
tryToClose(rs, LOG, WARNING);
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message getMessage(Connection txn, MessageId m) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
@@ -2887,6 +2879,22 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAccount(Connection txn, AuthorId a) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
String sql = "DELETE FROM localAuthors WHERE authorId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, a.getBytes());
|
||||
int affected = ps.executeUpdate();
|
||||
if (affected != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeContact(Connection txn, ContactId c)
|
||||
throws DbException {
|
||||
@@ -2969,23 +2977,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLocalAuthor(Connection txn, AuthorId a)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
String sql = "DELETE FROM localAuthors WHERE authorId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, a.getBytes());
|
||||
int affected = ps.executeUpdate();
|
||||
if (affected != 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessage(Connection txn, MessageId m) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
|
||||
@@ -7,7 +7,6 @@ import org.briarproject.bramble.api.identity.AuthorFactory;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.util.ByteUtils;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
|
||||
@@ -23,12 +22,10 @@ import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
|
||||
class AuthorFactoryImpl implements AuthorFactory {
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
private final Clock clock;
|
||||
|
||||
@Inject
|
||||
AuthorFactoryImpl(CryptoComponent crypto, Clock clock) {
|
||||
AuthorFactoryImpl(CryptoComponent crypto) {
|
||||
this.crypto = crypto;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,21 +41,12 @@ class AuthorFactoryImpl implements AuthorFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalAuthor createLocalAuthor(String name, boolean handshakeKeys) {
|
||||
public LocalAuthor createLocalAuthor(String name) {
|
||||
KeyPair signatureKeyPair = crypto.generateSignatureKeyPair();
|
||||
byte[] sigPub = signatureKeyPair.getPublic().getEncoded();
|
||||
byte[] sigPriv = signatureKeyPair.getPrivate().getEncoded();
|
||||
AuthorId id = getId(FORMAT_VERSION, name, sigPub);
|
||||
if (handshakeKeys) {
|
||||
KeyPair handshakeKeyPair = crypto.generateAgreementKeyPair();
|
||||
byte[] handPub = handshakeKeyPair.getPublic().getEncoded();
|
||||
byte[] handPriv = handshakeKeyPair.getPrivate().getEncoded();
|
||||
return new LocalAuthor(id, FORMAT_VERSION, name, sigPub, sigPriv,
|
||||
handPub, handPriv, clock.currentTimeMillis());
|
||||
} else {
|
||||
return new LocalAuthor(id, FORMAT_VERSION, name, sigPub, sigPriv,
|
||||
clock.currentTimeMillis());
|
||||
}
|
||||
byte[] publicKey = signatureKeyPair.getPublic().getEncoded();
|
||||
byte[] privateKey = signatureKeyPair.getPrivate().getEncoded();
|
||||
AuthorId id = getId(FORMAT_VERSION, name, publicKey);
|
||||
return new LocalAuthor(id, FORMAT_VERSION, name, publicKey, privateKey);
|
||||
}
|
||||
|
||||
private AuthorId getId(int formatVersion, String name, byte[] publicKey) {
|
||||
|
||||
@@ -5,11 +5,13 @@ import org.briarproject.bramble.api.crypto.KeyPair;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Account;
|
||||
import org.briarproject.bramble.api.identity.AuthorFactory;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager.OpenDatabaseHook;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Logger;
|
||||
@@ -32,87 +34,94 @@ class IdentityManagerImpl implements IdentityManager, OpenDatabaseHook {
|
||||
private final DatabaseComponent db;
|
||||
private final CryptoComponent crypto;
|
||||
private final AuthorFactory authorFactory;
|
||||
private final Clock clock;
|
||||
|
||||
// The local author is immutable so we can cache it
|
||||
@Nullable
|
||||
private volatile LocalAuthor cachedAuthor;
|
||||
private volatile Account cachedAccount;
|
||||
|
||||
@Inject
|
||||
IdentityManagerImpl(DatabaseComponent db, CryptoComponent crypto,
|
||||
AuthorFactory authorFactory) {
|
||||
AuthorFactory authorFactory, Clock clock) {
|
||||
this.db = db;
|
||||
this.crypto = crypto;
|
||||
this.authorFactory = authorFactory;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalAuthor createLocalAuthor(String name) {
|
||||
long start = now();
|
||||
LocalAuthor localAuthor = authorFactory.createLocalAuthor(name, true);
|
||||
LocalAuthor localAuthor = authorFactory.createLocalAuthor(name);
|
||||
logDuration(LOG, "Creating local author", start);
|
||||
return localAuthor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerLocalAuthor(LocalAuthor a) {
|
||||
cachedAuthor = a;
|
||||
LOG.info("Local author registered");
|
||||
public Account createAccount(String name) {
|
||||
long start = now();
|
||||
LocalAuthor localAuthor = authorFactory.createLocalAuthor(name);
|
||||
KeyPair handshakeKeyPair = crypto.generateAgreementKeyPair();
|
||||
byte[] handshakePub = handshakeKeyPair.getPublic().getEncoded();
|
||||
byte[] handshakePriv = handshakeKeyPair.getPrivate().getEncoded();
|
||||
logDuration(LOG, "Creating account", start);
|
||||
return new Account(localAuthor, handshakePub, handshakePriv,
|
||||
clock.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAccount(Account a) {
|
||||
if (!a.hasHandshakeKeyPair()) throw new IllegalArgumentException();
|
||||
cachedAccount = a;
|
||||
LOG.info("Account registered");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDatabaseOpened(Transaction txn) throws DbException {
|
||||
LocalAuthor cached = cachedAuthor;
|
||||
Account cached = cachedAccount;
|
||||
if (cached == null) {
|
||||
LocalAuthor loaded = loadLocalAuthor(txn);
|
||||
if (loaded.getHandshakePublicKey() == null) {
|
||||
KeyPair handshakeKeyPair = crypto.generateAgreementKeyPair();
|
||||
byte[] handshakePublicKey =
|
||||
handshakeKeyPair.getPublic().getEncoded();
|
||||
byte[] handshakePrivateKey =
|
||||
handshakeKeyPair.getPrivate().getEncoded();
|
||||
db.setHandshakeKeyPair(txn, loaded.getId(),
|
||||
handshakePublicKey, handshakePrivateKey);
|
||||
cachedAuthor = new LocalAuthor(loaded.getId(),
|
||||
loaded.getFormatVersion(), loaded.getName(),
|
||||
loaded.getPublicKey(), loaded.getPrivateKey(),
|
||||
handshakePublicKey, handshakePrivateKey,
|
||||
loaded.getTimeCreated());
|
||||
LOG.info("Handshake key pair added");
|
||||
cached = loadAccount(txn);
|
||||
if (cached.hasHandshakeKeyPair()) {
|
||||
cachedAccount = cached;
|
||||
LOG.info("Account loaded");
|
||||
} else {
|
||||
cachedAuthor = loaded;
|
||||
LOG.info("Local author loaded");
|
||||
KeyPair handshakeKeyPair = crypto.generateAgreementKeyPair();
|
||||
byte[] handshakePub = handshakeKeyPair.getPublic().getEncoded();
|
||||
byte[] handshakePriv =
|
||||
handshakeKeyPair.getPrivate().getEncoded();
|
||||
db.setHandshakeKeyPair(txn, cached.getId(), handshakePub,
|
||||
handshakePriv);
|
||||
LOG.info("Handshake key pair stored");
|
||||
}
|
||||
} else {
|
||||
db.addLocalAuthor(txn, cached);
|
||||
LOG.info("Local author stored");
|
||||
db.addAccount(txn, cached);
|
||||
LOG.info("Account stored");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalAuthor getLocalAuthor() throws DbException {
|
||||
LocalAuthor cached = cachedAuthor;
|
||||
Account cached = cachedAccount;
|
||||
if (cached == null) {
|
||||
cachedAuthor = cached =
|
||||
db.transactionWithResult(true, this::loadLocalAuthor);
|
||||
LOG.info("Local author loaded");
|
||||
cachedAccount = cached =
|
||||
db.transactionWithResult(true, this::loadAccount);
|
||||
LOG.info("Account loaded");
|
||||
}
|
||||
return cached;
|
||||
return cached.getLocalAuthor();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public LocalAuthor getLocalAuthor(Transaction txn) throws DbException {
|
||||
LocalAuthor cached = cachedAuthor;
|
||||
Account cached = cachedAccount;
|
||||
if (cached == null) {
|
||||
cachedAuthor = cached = loadLocalAuthor(txn);
|
||||
LOG.info("Local author loaded");
|
||||
cachedAccount = cached = loadAccount(txn);
|
||||
LOG.info("Account loaded");
|
||||
}
|
||||
return cached;
|
||||
return cached.getLocalAuthor();
|
||||
}
|
||||
|
||||
private LocalAuthor loadLocalAuthor(Transaction txn) throws DbException {
|
||||
Collection<LocalAuthor> authors = db.getLocalAuthors(txn);
|
||||
if (authors.size() != 1) throw new IllegalStateException();
|
||||
return authors.iterator().next();
|
||||
private Account loadAccount(Transaction txn) throws DbException {
|
||||
Collection<Account> accounts = db.getAccounts(txn);
|
||||
if (accounts.size() != 1) throw new DbException();
|
||||
return accounts.iterator().next();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user