Merge branch '1538-create-handshake-key-pair' into 'master'

Generate and store handshake key pair at startup if necessary

Closes #1538

See merge request briar/briar!1082
This commit is contained in:
Torsten Grote
2019-05-14 15:39:44 +00:00
65 changed files with 886 additions and 577 deletions

View File

@@ -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.Identity;
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);
Identity identity = identityManager.createIdentity(name);
identityManager.registerIdentity(identity);
SecretKey key = crypto.generateSecretKey();
if (!encryptAndStoreDatabaseKey(key, password)) return false;
databaseKey = key;

View File

@@ -15,7 +15,7 @@ import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener;
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.Identity;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.settings.Settings;
@@ -120,9 +120,9 @@ interface Database<T> {
HandshakeKeys k) throws DbException;
/**
* Stores a local pseudonym.
* Stores an identity.
*/
void addLocalAuthor(T txn, LocalAuthor a) throws DbException;
void addIdentity(T txn, Identity i) throws DbException;
/**
* Stores a message.
@@ -187,11 +187,12 @@ interface Database<T> {
boolean containsGroup(T txn, GroupId g) throws DbException;
/**
* Returns true if the database contains the given local pseudonym.
* Returns true if the database contains an identity for the given
* pseudonym.
* <p/>
* Read-only.
*/
boolean containsLocalAuthor(T txn, AuthorId a) throws DbException;
boolean containsIdentity(T txn, AuthorId a) throws DbException;
/**
* Returns true if the database contains the given message.
@@ -323,18 +324,18 @@ interface Database<T> {
throws DbException;
/**
* Returns the local pseudonym with the given ID.
* Returns the identity for local pseudonym with the given ID.
* <p/>
* Read-only.
*/
LocalAuthor getLocalAuthor(T txn, AuthorId a) throws DbException;
Identity getIdentity(T txn, AuthorId a) throws DbException;
/**
* Returns all local pseudonyms.
* Returns the identities for all local pseudonyms.
* <p/>
* Read-only.
*/
Collection<LocalAuthor> getLocalAuthors(T txn) throws DbException;
Collection<Identity> getIdentities(T txn) throws DbException;
/**
* Returns the message with the given ID.
@@ -629,9 +630,9 @@ interface Database<T> {
throws DbException;
/**
* Removes a local pseudonym (and all associated state) from the database.
* Removes an identity (and all associated state) from the database.
*/
void removeLocalAuthor(T txn, AuthorId a) throws DbException;
void removeIdentity(T txn, AuthorId a) throws DbException;
/**
* Removes a message (and all associated state) from the database.
@@ -685,6 +686,12 @@ interface Database<T> {
void setGroupVisibility(T txn, ContactId c, GroupId g, boolean shared)
throws DbException;
/**
* Sets the handshake key pair for the identity with the given ID.
*/
void setHandshakeKeyPair(T txn, AuthorId local, byte[] publicKey,
byte[] privateKey) throws DbException;
/**
* Marks the given message as shared.
*/

View File

@@ -20,7 +20,7 @@ import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.db.NoSuchGroupException;
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
import org.briarproject.bramble.api.db.NoSuchIdentityException;
import org.briarproject.bramble.api.db.NoSuchMessageException;
import org.briarproject.bramble.api.db.NoSuchPendingContactException;
import org.briarproject.bramble.api.db.NoSuchTransportException;
@@ -32,9 +32,9 @@ import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor;
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.identity.Identity;
import org.briarproject.bramble.api.identity.event.IdentityAddedEvent;
import org.briarproject.bramble.api.identity.event.IdentityRemovedEvent;
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
@@ -237,9 +237,9 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsLocalAuthor(txn, local))
throw new NoSuchLocalAuthorException();
if (db.containsLocalAuthor(txn, remote.getId()))
if (!db.containsIdentity(txn, local))
throw new NoSuchIdentityException();
if (db.containsIdentity(txn, remote.getId()))
throw new ContactExistsException();
if (db.containsContact(txn, remote.getId(), local))
throw new ContactExistsException();
@@ -283,13 +283,13 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
}
@Override
public void addLocalAuthor(Transaction transaction, LocalAuthor a)
public void addIdentity(Transaction transaction, Identity i)
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()));
if (!db.containsIdentity(txn, i.getId())) {
db.addIdentity(txn, i);
transaction.attach(new IdentityAddedEvent(i.getId()));
}
}
@@ -345,8 +345,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
public boolean containsContact(Transaction transaction, AuthorId remote,
AuthorId local) throws DbException {
T txn = unbox(transaction);
if (!db.containsLocalAuthor(txn, local))
throw new NoSuchLocalAuthorException();
if (!db.containsIdentity(txn, local))
throw new NoSuchIdentityException();
return db.containsContact(txn, remote, local);
}
@@ -358,10 +358,10 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
}
@Override
public boolean containsLocalAuthor(Transaction transaction, AuthorId local)
public boolean containsIdentity(Transaction transaction, AuthorId a)
throws DbException {
T txn = unbox(transaction);
return db.containsLocalAuthor(txn, local);
return db.containsIdentity(txn, a);
}
@Override
@@ -505,8 +505,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
public Collection<ContactId> getContacts(Transaction transaction,
AuthorId a) throws DbException {
T txn = unbox(transaction);
if (!db.containsLocalAuthor(txn, a))
throw new NoSuchLocalAuthorException();
if (!db.containsIdentity(txn, a))
throw new NoSuchIdentityException();
return db.getContacts(txn, a);
}
@@ -554,19 +554,19 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
}
@Override
public LocalAuthor getLocalAuthor(Transaction transaction, AuthorId a)
public Identity getIdentity(Transaction transaction, AuthorId a)
throws DbException {
T txn = unbox(transaction);
if (!db.containsLocalAuthor(txn, a))
throw new NoSuchLocalAuthorException();
return db.getLocalAuthor(txn, a);
if (!db.containsIdentity(txn, a))
throw new NoSuchIdentityException();
return db.getIdentity(txn, a);
}
@Override
public Collection<LocalAuthor> getLocalAuthors(Transaction transaction)
public Collection<Identity> getIdentities(Transaction transaction)
throws DbException {
T txn = unbox(transaction);
return db.getLocalAuthors(txn);
return db.getIdentities(txn);
}
@Override
@@ -905,14 +905,14 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
}
@Override
public void removeLocalAuthor(Transaction transaction, AuthorId a)
public void removeIdentity(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));
if (!db.containsIdentity(txn, a))
throw new NoSuchIdentityException();
db.removeIdentity(txn, a);
transaction.attach(new IdentityRemovedEvent(a));
}
@Override
@@ -1035,6 +1035,16 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
}
}
@Override
public void setHandshakeKeyPair(Transaction transaction, AuthorId local,
byte[] publicKey, byte[] privateKey) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsIdentity(txn, local))
throw new NoSuchIdentityException();
db.setHandshakeKeyPair(txn, local, publicKey, privateKey);
}
@Override
public void setReorderingWindow(Transaction transaction,
TransportKeySetId k, TransportId t, long timePeriod, long base,

View File

@@ -15,6 +15,7 @@ import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
@@ -874,8 +875,7 @@ abstract class JdbcDatabase implements Database<Connection> {
}
@Override
public void addLocalAuthor(Connection txn, LocalAuthor a)
throws DbException {
public void addIdentity(Connection txn, Identity i) throws DbException {
PreparedStatement ps = null;
try {
String sql = "INSERT INTO localAuthors"
@@ -883,16 +883,17 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " 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());
LocalAuthor local = i.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 (i.getHandshakePublicKey() == null) ps.setNull(6, BINARY);
else ps.setBytes(6, i.getHandshakePublicKey());
if (i.getHandshakePrivateKey() == null) ps.setNull(7, BINARY);
else ps.setBytes(7, i.getHandshakePrivateKey());
ps.setLong(8, i.getTimeCreated());
int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException();
ps.close();
@@ -1248,7 +1249,7 @@ abstract class JdbcDatabase implements Database<Connection> {
}
@Override
public boolean containsLocalAuthor(Connection txn, AuthorId a)
public boolean containsIdentity(Connection txn, AuthorId a)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
@@ -1660,41 +1661,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);
LocalAuthor localAuthor = new LocalAuthor(a, formatVersion, name,
publicKey, privateKey, handshakePublicKey,
handshakePrivateKey, created);
if (rs.next()) throw new DbStateException();
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 {
@@ -1776,30 +1742,69 @@ abstract class JdbcDatabase implements Database<Connection> {
}
@Override
public Collection<LocalAuthor> getLocalAuthors(Connection txn)
public Identity getIdentity(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 Identity(local, handshakePublicKey, handshakePrivateKey,
created);
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public Collection<Identity> getIdentities(Connection txn)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT authorId, formatVersion, name, publicKey,"
+ " privateKey, created"
+ " privateKey, handshakePublicKey, handshakePrivateKey,"
+ " created"
+ " FROM localAuthors";
ps = txn.prepareStatement(sql);
rs = ps.executeQuery();
List<LocalAuthor> authors = new ArrayList<>();
List<Identity> identities = 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);
long created = rs.getLong(6);
authors.add(new LocalAuthor(authorId, formatVersion, name,
publicKey, privateKey, created));
byte[] handshakePublicKey = rs.getBytes(6);
byte[] handshakePrivateKey = rs.getBytes(7);
long created = rs.getLong(8);
LocalAuthor local = new LocalAuthor(authorId, formatVersion,
name, publicKey, privateKey);
identities.add(new Identity(local, handshakePublicKey,
handshakePrivateKey, created));
}
rs.close();
ps.close();
return authors;
return identities;
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
@@ -2958,8 +2963,7 @@ abstract class JdbcDatabase implements Database<Connection> {
}
@Override
public void removeLocalAuthor(Connection txn, AuthorId a)
throws DbException {
public void removeIdentity(Connection txn, AuthorId a) throws DbException {
PreparedStatement ps = null;
try {
String sql = "DELETE FROM localAuthors WHERE authorId = ?";
@@ -3176,6 +3180,27 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public void setHandshakeKeyPair(Connection txn, AuthorId local,
byte[] publicKey, byte[] privateKey) throws DbException {
PreparedStatement ps = null;
try {
String sql = "UPDATE localAuthors"
+ " SET handshakePublicKey = ?, handshakePrivateKey = ?"
+ " WHERE authorId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, publicKey);
ps.setBytes(2, privateKey);
ps.setBytes(3, local.getBytes());
int affected = ps.executeUpdate();
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public void setMessageShared(Connection txn, MessageId m)
throws DbException {

View File

@@ -1,12 +1,12 @@
package org.briarproject.bramble.identity;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.identity.Author;
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;
@@ -22,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
@@ -43,17 +41,12 @@ class AuthorFactoryImpl implements AuthorFactory {
}
@Override
public LocalAuthor createLocalAuthor(String name, byte[] publicKey,
byte[] privateKey) {
return createLocalAuthor(FORMAT_VERSION, name, publicKey, privateKey);
}
@Override
public LocalAuthor createLocalAuthor(int formatVersion, String name,
byte[] publicKey, byte[] privateKey) {
AuthorId id = getId(formatVersion, name, publicKey);
return new LocalAuthor(id, formatVersion, name, publicKey, privateKey,
clock.currentTimeMillis());
public LocalAuthor createLocalAuthor(String name) {
KeyPair signatureKeyPair = crypto.generateSignatureKeyPair();
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) {

View File

@@ -6,97 +6,164 @@ 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.AuthorFactory;
import org.briarproject.bramble.api.identity.Identity;
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;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.now;
@ThreadSafe
@NotNullByDefault
class IdentityManagerImpl implements IdentityManager {
class IdentityManagerImpl implements IdentityManager, OpenDatabaseHook {
private static final Logger LOG =
Logger.getLogger(IdentityManagerImpl.class.getName());
getLogger(IdentityManagerImpl.class.getName());
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
/**
* The user's identity, or null if no identity has been registered or
* loaded. If non-null, this identity always has handshake keys.
*/
@Nullable
private volatile LocalAuthor cachedAuthor;
private volatile Identity cachedIdentity = null;
/**
* True if {@code cachedIdentity} was registered via
* {@link #registerIdentity(Identity)} and should be stored when
* {@link #onDatabaseOpened(Transaction)} is called.
*/
private volatile boolean shouldStoreIdentity = false;
/**
* True if the handshake keys in {@code cachedIdentity} were generated
* when the identity was loaded and should be stored when
* {@link #onDatabaseOpened(Transaction)} is called.
*/
private volatile boolean shouldStoreKeys = false;
@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) {
public Identity createIdentity(String name) {
long start = now();
KeyPair keyPair = crypto.generateSignatureKeyPair();
byte[] publicKey = keyPair.getPublic().getEncoded();
byte[] privateKey = keyPair.getPrivate().getEncoded();
LocalAuthor localAuthor = authorFactory.createLocalAuthor(name,
publicKey, privateKey);
logDuration(LOG, "Creating local author", start);
return localAuthor;
LocalAuthor localAuthor = authorFactory.createLocalAuthor(name);
KeyPair handshakeKeyPair = crypto.generateAgreementKeyPair();
byte[] handshakePub = handshakeKeyPair.getPublic().getEncoded();
byte[] handshakePriv = handshakeKeyPair.getPrivate().getEncoded();
logDuration(LOG, "Creating identity", start);
return new Identity(localAuthor, handshakePub, handshakePriv,
clock.currentTimeMillis());
}
@Override
public void registerLocalAuthor(LocalAuthor a) {
cachedAuthor = a;
LOG.info("Local author registered");
public void registerIdentity(Identity i) {
if (!i.hasHandshakeKeyPair()) throw new IllegalArgumentException();
cachedIdentity = i;
shouldStoreIdentity = true;
LOG.info("Identity registered");
}
@Override
public void storeLocalAuthor() throws DbException {
LocalAuthor cached = cachedAuthor;
if (cached == null) {
LOG.info("No local author to store");
return;
public void onDatabaseOpened(Transaction txn) throws DbException {
Identity cached = getCachedIdentity(txn);
if (shouldStoreIdentity) {
// The identity was registered at startup - store it
db.addIdentity(txn, cached);
LOG.info("Identity stored");
} else if (shouldStoreKeys) {
// Handshake keys were generated when loading the identity -
// store them
byte[] handshakePub =
requireNonNull(cached.getHandshakePublicKey());
byte[] handshakePriv =
requireNonNull(cached.getHandshakePrivateKey());
db.setHandshakeKeyPair(txn, cached.getId(), handshakePub,
handshakePriv);
LOG.info("Handshake key pair stored");
}
db.transaction(false, txn -> db.addLocalAuthor(txn, cached));
LOG.info("Local author stored");
}
@Override
public LocalAuthor getLocalAuthor() throws DbException {
if (cachedAuthor == null) {
cachedAuthor =
db.transactionWithResult(true, this::loadLocalAuthor);
LOG.info("Local author loaded");
}
LocalAuthor cached = cachedAuthor;
if (cached == null) throw new AssertionError();
return cached;
Identity cached = cachedIdentity;
if (cached == null)
cached = db.transactionWithResult(true, this::getCachedIdentity);
return cached.getLocalAuthor();
}
@Override
public LocalAuthor getLocalAuthor(Transaction txn) throws DbException {
if (cachedAuthor == null) {
cachedAuthor = loadLocalAuthor(txn);
LOG.info("Local author loaded");
}
LocalAuthor cached = cachedAuthor;
if (cached == null) throw new AssertionError();
return getCachedIdentity(txn).getLocalAuthor();
}
@Override
public byte[][] getHandshakeKeys(Transaction txn) throws DbException {
Identity cached = getCachedIdentity(txn);
return new byte[][] {
cached.getHandshakePublicKey(),
cached.getHandshakePrivateKey()
};
}
/**
* Loads the identity if necessary and returns it. If
* {@code cachedIdentity} was not already set by calling
* {@link #registerIdentity(Identity)}, this method sets it. If
* {@code cachedIdentity} was already set, either by calling
* {@link #registerIdentity(Identity)} or by a previous call to this
* method, then this method returns the cached identity without hitting
* the database.
*/
private Identity getCachedIdentity(Transaction txn) throws DbException {
Identity cached = cachedIdentity;
if (cached == null)
cachedIdentity = cached = loadIdentityWithKeyPair(txn);
return cached;
}
private LocalAuthor loadLocalAuthor(Transaction txn) throws DbException {
return db.getLocalAuthors(txn).iterator().next();
/**
* Loads and returns the identity, generating a handshake key pair if
* necessary and setting {@code shouldStoreKeys} if a handshake key pair
* was generated.
*/
private Identity loadIdentityWithKeyPair(Transaction txn)
throws DbException {
Collection<Identity> identities = db.getIdentities(txn);
if (identities.size() != 1) throw new DbException();
Identity i = identities.iterator().next();
LOG.info("Identity loaded");
if (i.hasHandshakeKeyPair()) return i;
KeyPair handshakeKeyPair = crypto.generateAgreementKeyPair();
byte[] handshakePub = handshakeKeyPair.getPublic().getEncoded();
byte[] handshakePriv = handshakeKeyPair.getPrivate().getEncoded();
LOG.info("Handshake key pair generated");
shouldStoreKeys = true;
return new Identity(i.getLocalAuthor(), handshakePub, handshakePriv,
i.getTimeCreated());
}
}

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble.identity;
import org.briarproject.bramble.api.identity.AuthorFactory;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -24,8 +25,9 @@ public class IdentityModule {
@Provides
@Singleton
IdentityManager provideIdentityManager(
IdentityManager provideIdentityManager(LifecycleManager lifecycleManager,
IdentityManagerImpl identityManager) {
lifecycleManager.registerOpenDatabaseHook(identityManager);
return identityManager;
}
}

View File

@@ -7,13 +7,11 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.lifecycle.ServiceException;
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Client;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -28,6 +26,7 @@ import javax.inject.Inject;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.COMPACTING_DATABASE;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
@@ -49,14 +48,13 @@ import static org.briarproject.bramble.util.LogUtils.now;
class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
private static final Logger LOG =
Logger.getLogger(LifecycleManagerImpl.class.getName());
getLogger(LifecycleManagerImpl.class.getName());
private final DatabaseComponent db;
private final EventBus eventBus;
private final List<Service> services;
private final List<Client> clients;
private final List<OpenDatabaseHook> openDatabaseHooks;
private final List<ExecutorService> executors;
private final IdentityManager identityManager;
private final Semaphore startStopSemaphore = new Semaphore(1);
private final CountDownLatch dbLatch = new CountDownLatch(1);
private final CountDownLatch startupLatch = new CountDownLatch(1);
@@ -65,13 +63,11 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
private volatile LifecycleState state = STARTING;
@Inject
LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus,
IdentityManager identityManager) {
LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus) {
this.db = db;
this.eventBus = eventBus;
this.identityManager = identityManager;
services = new CopyOnWriteArrayList<>();
clients = new CopyOnWriteArrayList<>();
openDatabaseHooks = new CopyOnWriteArrayList<>();
executors = new CopyOnWriteArrayList<>();
}
@@ -83,10 +79,12 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
}
@Override
public void registerClient(Client c) {
if (LOG.isLoggable(INFO))
LOG.info("Registering client " + c.getClass().getSimpleName());
clients.add(c);
public void registerOpenDatabaseHook(OpenDatabaseHook hook) {
if (LOG.isLoggable(INFO)) {
LOG.info("Registering open database hook "
+ hook.getClass().getSimpleName());
}
openDatabaseHooks.add(hook);
}
@Override
@@ -102,28 +100,28 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
return ALREADY_RUNNING;
}
try {
LOG.info("Starting services");
LOG.info("Opening database");
long start = now();
boolean reopened = db.open(dbKey, this);
if (reopened) logDuration(LOG, "Reopening database", start);
else logDuration(LOG, "Creating database", start);
identityManager.storeLocalAuthor();
db.transaction(false, txn -> {
for (OpenDatabaseHook hook : openDatabaseHooks) {
long start1 = now();
hook.onDatabaseOpened(txn);
if (LOG.isLoggable(FINE)) {
logDuration(LOG, "Calling open database hook "
+ hook.getClass().getSimpleName(), start1);
}
}
});
LOG.info("Starting services");
state = STARTING_SERVICES;
dbLatch.countDown();
eventBus.broadcast(new LifecycleEvent(STARTING_SERVICES));
db.transaction(false, txn -> {
for (Client c : clients) {
long start1 = now();
c.createLocalState(txn);
if (LOG.isLoggable(FINE)) {
logDuration(LOG, "Starting client "
+ c.getClass().getSimpleName(), start1);
}
}
});
for (Service s : services) {
start = now();
s.startService();

View File

@@ -48,7 +48,7 @@ public class PropertiesModule {
ValidationManager validationManager, ContactManager contactManager,
ClientVersioningManager clientVersioningManager,
TransportPropertyManagerImpl transportPropertyManager) {
lifecycleManager.registerClient(transportPropertyManager);
lifecycleManager.registerOpenDatabaseHook(transportPropertyManager);
validationManager.registerIncomingMessageHook(CLIENT_ID, MAJOR_VERSION,
transportPropertyManager);
contactManager.registerContactHook(transportPropertyManager);

View File

@@ -13,11 +13,11 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.LifecycleManager.OpenDatabaseHook;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.properties.TransportPropertyManager;
import org.briarproject.bramble.api.sync.Client;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.Group.Visibility;
import org.briarproject.bramble.api.sync.GroupId;
@@ -40,7 +40,8 @@ import javax.inject.Inject;
@Immutable
@NotNullByDefault
class TransportPropertyManagerImpl implements TransportPropertyManager,
Client, ContactHook, ClientVersioningHook, IncomingMessageHook {
OpenDatabaseHook, ContactHook, ClientVersioningHook,
IncomingMessageHook {
private final DatabaseComponent db;
private final ClientHelper clientHelper;
@@ -67,7 +68,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
}
@Override
public void createLocalState(Transaction txn) throws DbException {
public void onDatabaseOpened(Transaction txn) throws DbException {
if (db.containsGroup(txn, localGroup.getId())) return;
db.addGroup(txn, localGroup);
// Set things up for any pre-existing contacts

View File

@@ -12,10 +12,10 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.LifecycleManager.OpenDatabaseHook;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.lifecycle.ServiceException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Client;
import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.Group.Visibility;
@@ -53,8 +53,8 @@ import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_
import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_UPDATE_VERSION;
@NotNullByDefault
class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
Service, ContactHook, IncomingMessageHook {
class ClientVersioningManagerImpl implements ClientVersioningManager,
Service, OpenDatabaseHook, ContactHook, IncomingMessageHook {
private final DatabaseComponent db;
private final ClientHelper clientHelper;
@@ -124,7 +124,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager, Client,
}
@Override
public void createLocalState(Transaction txn) throws DbException {
public void onDatabaseOpened(Transaction txn) throws DbException {
if (db.containsGroup(txn, localGroup.getId())) return;
db.addGroup(txn, localGroup);
// Set things up for any pre-existing contacts

View File

@@ -34,7 +34,7 @@ public class VersioningModule {
ClientVersioningManagerImpl clientVersioningManager,
LifecycleManager lifecycleManager, ContactManager contactManager,
ValidationManager validationManager) {
lifecycleManager.registerClient(clientVersioningManager);
lifecycleManager.registerOpenDatabaseHook(clientVersioningManager);
lifecycleManager.registerService(clientVersioningManager);
contactManager.registerContactHook(clientVersioningManager);
validationManager.registerIncomingMessageHook(CLIENT_ID, MAJOR_VERSION,

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.account;
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.Identity;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.test.BrambleMockTestCase;
@@ -24,7 +25,7 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getIdentity;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
@@ -47,7 +48,8 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
private final String encryptedKeyHex = toHexString(encryptedKey);
private final byte[] newEncryptedKey = getRandomBytes(123);
private final String newEncryptedKeyHex = toHexString(newEncryptedKey);
private final LocalAuthor localAuthor = getLocalAuthor();
private final Identity identity = getIdentity();
private final LocalAuthor localAuthor = identity.getLocalAuthor();
private final String authorName = localAuthor.getName();
private final String password = getRandomString(10);
private final String newPassword = getRandomString(10);
@@ -251,9 +253,9 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
@Test
public void testCreateAccountStoresDbKey() throws Exception {
context.checking(new Expectations() {{
oneOf(identityManager).createLocalAuthor(authorName);
will(returnValue(localAuthor));
oneOf(identityManager).registerLocalAuthor(localAuthor);
oneOf(identityManager).createIdentity(authorName);
will(returnValue(identity));
oneOf(identityManager).registerIdentity(identity);
oneOf(crypto).generateSecretKey();
will(returnValue(key));
oneOf(crypto).encryptWithPassword(key.getBytes(), password);

View File

@@ -11,16 +11,17 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.db.NoSuchGroupException;
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
import org.briarproject.bramble.api.db.NoSuchIdentityException;
import org.briarproject.bramble.api.db.NoSuchMessageException;
import org.briarproject.bramble.api.db.NoSuchPendingContactException;
import org.briarproject.bramble.api.db.NoSuchTransportException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.Identity;
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.identity.event.IdentityAddedEvent;
import org.briarproject.bramble.api.identity.event.IdentityRemovedEvent;
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.settings.Settings;
@@ -65,6 +66,7 @@ import java.util.concurrent.atomic.AtomicReference;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
@@ -77,8 +79,9 @@ import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getClientId;
import static org.briarproject.bramble.test.TestUtils.getContact;
import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getIdentity;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTransportId;
@@ -104,6 +107,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
private final GroupId groupId;
private final Group group;
private final Author author;
private final Identity identity;
private final LocalAuthor localAuthor;
private final String alias;
private final Message message, message1;
@@ -122,7 +126,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
group = getGroup(clientId, majorVersion);
groupId = group.getId();
author = getAuthor();
localAuthor = getLocalAuthor();
identity = getIdentity();
localAuthor = identity.getLocalAuthor();
message = getMessage(groupId);
message1 = getMessage(groupId);
messageId = message.getId();
@@ -157,15 +162,15 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
// startTransaction()
oneOf(database).startTransaction();
will(returnValue(txn));
// registerLocalAuthor()
oneOf(database).containsLocalAuthor(txn, localAuthor.getId());
// addIdentity()
oneOf(database).containsIdentity(txn, localAuthor.getId());
will(returnValue(false));
oneOf(database).addLocalAuthor(txn, localAuthor);
oneOf(eventBus).broadcast(with(any(LocalAuthorAddedEvent.class)));
oneOf(database).addIdentity(txn, identity);
oneOf(eventBus).broadcast(with(any(IdentityAddedEvent.class)));
// addContact()
oneOf(database).containsLocalAuthor(txn, localAuthor.getId());
oneOf(database).containsIdentity(txn, localAuthor.getId());
will(returnValue(true));
oneOf(database).containsLocalAuthor(txn, author.getId());
oneOf(database).containsIdentity(txn, author.getId());
will(returnValue(false));
oneOf(database).containsContact(txn, author.getId(),
localAuthor.getId());
@@ -201,11 +206,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
will(returnValue(true));
oneOf(database).removeContact(txn, contactId);
oneOf(eventBus).broadcast(with(any(ContactRemovedEvent.class)));
// removeLocalAuthor()
oneOf(database).containsLocalAuthor(txn, localAuthor.getId());
// removeIdentity()
oneOf(database).containsIdentity(txn, localAuthor.getId());
will(returnValue(true));
oneOf(database).removeLocalAuthor(txn, localAuthor.getId());
oneOf(eventBus).broadcast(with(any(LocalAuthorRemovedEvent.class)));
oneOf(database).removeIdentity(txn, localAuthor.getId());
oneOf(eventBus).broadcast(with(any(IdentityRemovedEvent.class)));
// endTransaction()
oneOf(database).commitTransaction(txn);
// close()
@@ -216,7 +221,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
assertFalse(db.open(key, null));
db.transaction(false, transaction -> {
db.addLocalAuthor(transaction, localAuthor);
db.addIdentity(transaction, identity);
assertEquals(contactId, db.addContact(transaction, author,
localAuthor.getId(), true));
assertEquals(singletonList(contact),
@@ -227,7 +232,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
db.getGroups(transaction, clientId, majorVersion));
db.removeGroup(transaction, group);
db.removeContact(transaction, contactId);
db.removeLocalAuthor(transaction, localAuthor.getId());
db.removeIdentity(transaction, localAuthor.getId());
});
db.close();
}
@@ -432,16 +437,15 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
}
@Test
public void testVariousMethodsThrowExceptionIfLocalAuthorIsMissing()
public void testVariousMethodsThrowExceptionIfIdentityIsMissing()
throws Exception {
context.checking(new Expectations() {{
// Check whether the pseudonym is in the DB (which it's not)
exactly(3).of(database).startTransaction();
// Check whether the identity is in the DB (which it's not)
exactly(4).of(database).startTransaction();
will(returnValue(txn));
exactly(3).of(database).containsLocalAuthor(txn,
localAuthor.getId());
exactly(4).of(database).containsIdentity(txn, localAuthor.getId());
will(returnValue(false));
exactly(3).of(database).abortTransaction(txn);
exactly(4).of(database).abortTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager);
@@ -451,23 +455,34 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
db.addContact(transaction, author, localAuthor.getId(),
true));
fail();
} catch (NoSuchLocalAuthorException expected) {
} catch (NoSuchIdentityException expected) {
// Expected
}
try {
db.transaction(false, transaction ->
db.getLocalAuthor(transaction, localAuthor.getId()));
db.getIdentity(transaction, localAuthor.getId()));
fail();
} catch (NoSuchLocalAuthorException expected) {
} catch (NoSuchIdentityException expected) {
// Expected
}
try {
db.transaction(false, transaction ->
db.removeLocalAuthor(transaction, localAuthor.getId()));
db.removeIdentity(transaction, localAuthor.getId()));
fail();
} catch (NoSuchLocalAuthorException expected) {
} catch (NoSuchIdentityException expected) {
// Expected
}
try {
byte[] publicKey = getRandomBytes(MAX_AGREEMENT_PUBLIC_KEY_BYTES);
byte[] privateKey = getRandomBytes(123);
db.transaction(false, transaction ->
db.setHandshakeKeyPair(transaction, localAuthor.getId(),
publicKey, privateKey));
fail();
} catch (NoSuchIdentityException expected) {
// Expected
}
}
@@ -1403,10 +1418,10 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsLocalAuthor(txn, localAuthor.getId());
oneOf(database).containsIdentity(txn, localAuthor.getId());
will(returnValue(true));
// Contact is a local identity
oneOf(database).containsLocalAuthor(txn, author.getId());
oneOf(database).containsIdentity(txn, author.getId());
will(returnValue(true));
oneOf(database).abortTransaction(txn);
}});
@@ -1429,9 +1444,9 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsLocalAuthor(txn, localAuthor.getId());
oneOf(database).containsIdentity(txn, localAuthor.getId());
will(returnValue(true));
oneOf(database).containsLocalAuthor(txn, author.getId());
oneOf(database).containsIdentity(txn, author.getId());
will(returnValue(false));
// Contact already exists for this local identity
oneOf(database).containsContact(txn, author.getId(),
@@ -1454,7 +1469,6 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
}
@Test
@SuppressWarnings("unchecked")
public void testMessageDependencies() throws Exception {
int shutdownHandle = 12345;
MessageId messageId2 = new MessageId(getRandomId());

View File

@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.bramble.api.sync.Group;
@@ -37,7 +38,7 @@ import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERE
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getIdentity;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
@@ -161,11 +162,11 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
}
@Test
public void testContainsLocalAuthor() throws Exception {
String name = "containsLocalAuthor(T, AuthorId)";
public void testContainsIdentity() throws Exception {
String name = "containsIdentity(T, AuthorId)";
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.containsLocalAuthor(txn, localAuthor.getId());
db.containsIdentity(txn, localAuthor.getId());
db.commitTransaction(txn);
});
}
@@ -295,21 +296,21 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
}
@Test
public void testGetLocalAuthor() throws Exception {
String name = "getLocalAuthor(T, AuthorId)";
public void testGetIdentity() throws Exception {
String name = "getIdentity(T, AuthorId)";
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.getLocalAuthor(txn, localAuthor.getId());
db.getIdentity(txn, localAuthor.getId());
db.commitTransaction(txn);
});
}
@Test
public void testGetLocalAuthors() throws Exception {
String name = "getLocalAuthors(T)";
public void testGetIdentities() throws Exception {
String name = "getIdentities(T)";
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.getLocalAuthors(txn);
db.getIdentities(txn);
db.commitTransaction(txn);
});
}
@@ -531,7 +532,8 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
}
void populateDatabase(Database<Connection> db) throws DbException {
localAuthor = getLocalAuthor();
Identity identity = getIdentity();
localAuthor = identity.getLocalAuthor();
clientIds = new ArrayList<>();
contacts = new ArrayList<>();
groups = new ArrayList<>();
@@ -543,7 +545,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
for (int i = 0; i < CLIENTS; i++) clientIds.add(getClientId());
Connection txn = db.startTransaction();
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
for (int i = 0; i < CONTACTS; i++) {
ContactId c = db.addContact(txn, getAuthor(), localAuthor.getId(),
random.nextBoolean());

View File

@@ -9,6 +9,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.identity.Author;
import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.settings.Settings;
@@ -57,6 +58,7 @@ import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.bramble.api.contact.PendingContactState.FAILED;
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES;
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
@@ -73,9 +75,10 @@ import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
import static org.briarproject.bramble.test.TestUtils.getAuthor;
import static org.briarproject.bramble.test.TestUtils.getClientId;
import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static org.briarproject.bramble.test.TestUtils.getIdentity;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getPendingContact;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
@@ -103,6 +106,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
private final int majorVersion;
private final Group group;
private final Author author;
private final Identity identity;
private final LocalAuthor localAuthor;
private final Message message;
private final MessageId messageId;
@@ -119,7 +123,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
group = getGroup(clientId, majorVersion);
groupId = group.getId();
author = getAuthor();
localAuthor = getLocalAuthor();
identity = getIdentity();
localAuthor = identity.getLocalAuthor();
message = getMessage(groupId);
messageId = message.getId();
transportId = getTransportId();
@@ -145,7 +150,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
assertFalse(db.containsContact(txn, contactId));
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
assertTrue(db.containsContact(txn, contactId));
@@ -208,7 +213,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact, a shared group and a shared message
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -239,7 +244,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact, a shared group and a shared but unvalidated message
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -284,7 +289,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact, an invisible group and a shared message
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -335,7 +340,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact, a shared group and an unshared message
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -366,7 +371,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact, a shared group and a shared message
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -393,7 +398,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact and a visible group
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -434,7 +439,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact, a shared group and a shared message
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -566,7 +571,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact and a shared group
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -586,7 +591,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
@@ -604,7 +609,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact, an invisible group and a message
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -623,7 +628,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact and a group
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -675,7 +680,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertEquals(emptyList(), db.getTransportKeys(txn, transportId));
// Add the contact, the transport and the transport keys
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addTransport(txn, transportId, 123);
@@ -776,7 +781,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertEquals(emptyList(), db.getHandshakeKeys(txn, transportId));
// Add the contact, the transport and the handshake keys
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addTransport(txn, transportId, 123);
@@ -929,7 +934,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add the contact, transport and transport keys
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addTransport(txn, transportId, 123);
@@ -973,7 +978,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add the contact, transport and handshake keys
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addTransport(txn, transportId, 123);
@@ -1020,7 +1025,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add the contact, transport and transport keys
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addTransport(txn, transportId, 123);
@@ -1067,7 +1072,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add the contact, transport and handshake keys
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addTransport(txn, transportId, 123);
@@ -1109,14 +1114,15 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a local author - no contacts should be associated
db.addLocalAuthor(txn, localAuthor);
// Add an identity for a local author - no contacts should be
// associated
db.addIdentity(txn, identity);
// Add a contact associated with the local author
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
// Ensure contact is returned from database by Author ID
// Ensure contact is returned from database by author ID
Collection<Contact> contacts =
db.getContactsByAuthorId(txn, author.getId());
assertEquals(1, contacts.size());
@@ -1136,8 +1142,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a local author - no contacts should be associated
db.addLocalAuthor(txn, localAuthor);
// Add an identity for a local author - no contacts should be
// associated
db.addIdentity(txn, identity);
Collection<ContactId> contacts =
db.getContacts(txn, localAuthor.getId());
assertEquals(emptyList(), contacts);
@@ -1148,8 +1155,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
contacts = db.getContacts(txn, localAuthor.getId());
assertEquals(singletonList(contactId), contacts);
// Remove the local author - the contact should be removed
db.removeLocalAuthor(txn, localAuthor.getId());
// Remove the identity - the contact should be removed
db.removeIdentity(txn, localAuthor.getId());
contacts = db.getContacts(txn, localAuthor.getId());
assertEquals(emptyList(), contacts);
assertFalse(db.containsContact(txn, contactId));
@@ -1164,7 +1171,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact - initially there should be no offered messages
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
assertEquals(0, db.countOfferedMessages(txn, contactId));
@@ -1748,7 +1755,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact, a shared group and a shared message
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -1850,14 +1857,15 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test
public void testDifferentLocalAuthorsCanHaveTheSameContact()
throws Exception {
LocalAuthor localAuthor1 = getLocalAuthor();
Identity identity1 = getIdentity();
LocalAuthor localAuthor1 = identity1.getLocalAuthor();
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add two local authors
db.addLocalAuthor(txn, localAuthor);
db.addLocalAuthor(txn, localAuthor1);
// Add identities for two local authors
db.addIdentity(txn, identity);
db.addIdentity(txn, identity1);
// Add the same contact for each local author
ContactId contactId =
@@ -1881,7 +1889,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact, a shared group and a shared message
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -1935,7 +1943,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
@@ -1992,7 +2000,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact, a group and a message
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -2076,7 +2084,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact, a shared group and a shared message
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -2121,7 +2129,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
// Add a contact, a shared group and a shared message
db.addLocalAuthor(txn, localAuthor);
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), true));
db.addGroup(txn, group);
@@ -2237,6 +2245,30 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
db.close();
}
@Test
public void testSetHandshakeKeyPair() throws Exception {
Identity withoutKeys =
new Identity(localAuthor, null, null, identity.getTimeCreated());
assertFalse(withoutKeys.hasHandshakeKeyPair());
byte[] publicKey = getRandomBytes(MAX_AGREEMENT_PUBLIC_KEY_BYTES);
byte[] privateKey = getRandomBytes(123);
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
db.addIdentity(txn, withoutKeys);
Identity retrieved = db.getIdentity(txn, localAuthor.getId());
assertFalse(retrieved.hasHandshakeKeyPair());
db.setHandshakeKeyPair(txn, localAuthor.getId(), publicKey, privateKey);
retrieved = db.getIdentity(txn, localAuthor.getId());
assertTrue(retrieved.hasHandshakeKeyPair());
assertArrayEquals(publicKey, retrieved.getHandshakePublicKey());
assertArrayEquals(privateKey, retrieved.getHandshakePrivateKey());
db.commitTransaction(txn);
db.close();
}
private Database<Connection> open(boolean resume) throws Exception {
return open(resume, new TestMessageFactory(), new SystemClock());
}

View File

@@ -8,18 +8,17 @@ 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.AuthorFactory;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.jmock.Expectations;
import org.junit.Before;
import org.junit.Test;
import java.util.Collection;
import java.util.Collections;
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
import static java.util.Collections.singletonList;
import static org.briarproject.bramble.test.TestUtils.getIdentity;
import static org.junit.Assert.assertEquals;
public class IdentityManagerImplTest extends BrambleMockTestCase {
@@ -28,67 +27,100 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
private final AuthorFactory authorFactory =
context.mock(AuthorFactory.class);
private final PublicKey publicKey = context.mock(PublicKey.class);
private final PrivateKey privateKey = context.mock(PrivateKey.class);
private final Clock clock = context.mock(Clock.class);
private final PublicKey handshakePublicKey = context.mock(PublicKey.class);
private final PrivateKey handshakePrivateKey =
context.mock(PrivateKey.class);
private final Transaction txn = new Transaction(null, false);
private final LocalAuthor localAuthor = getLocalAuthor();
private final Collection<LocalAuthor> localAuthors =
Collections.singletonList(localAuthor);
private final String authorName = localAuthor.getName();
private final KeyPair keyPair = new KeyPair(publicKey, privateKey);
private final byte[] publicKeyBytes = localAuthor.getPublicKey();
private final byte[] privateKeyBytes = localAuthor.getPrivateKey();
private IdentityManager identityManager;
private final Identity identityWithKeys = getIdentity();
private final LocalAuthor localAuthor = identityWithKeys.getLocalAuthor();
private final Identity identityWithoutKeys = new Identity(localAuthor,
null, null, identityWithKeys.getTimeCreated());
private final KeyPair handshakeKeyPair =
new KeyPair(handshakePublicKey, handshakePrivateKey);
private final byte[] handshakePublicKeyBytes =
identityWithKeys.getHandshakePublicKey();
private final byte[] handshakePrivateKeyBytes =
identityWithKeys.getHandshakePrivateKey();
private IdentityManagerImpl identityManager;
@Before
public void setUp() {
identityManager = new IdentityManagerImpl(db, crypto, authorFactory);
identityManager =
new IdentityManagerImpl(db, crypto, authorFactory, clock);
}
@Test
public void testCreateLocalAuthor() {
public void testOpenDatabaseIdentityRegistered() throws Exception {
context.checking(new Expectations() {{
oneOf(crypto).generateSignatureKeyPair();
will(returnValue(keyPair));
oneOf(publicKey).getEncoded();
will(returnValue(publicKeyBytes));
oneOf(privateKey).getEncoded();
will(returnValue(privateKeyBytes));
oneOf(authorFactory).createLocalAuthor(authorName,
publicKeyBytes, privateKeyBytes);
will(returnValue(localAuthor));
oneOf(db).addIdentity(txn, identityWithKeys);
}});
assertEquals(localAuthor,
identityManager.createLocalAuthor(authorName));
identityManager.registerIdentity(identityWithKeys);
identityManager.onDatabaseOpened(txn);
}
@Test
public void testRegisterAndStoreLocalAuthor() throws Exception {
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn));
oneOf(db).addLocalAuthor(txn, localAuthor);
public void testOpenDatabaseHandshakeKeysGenerated() throws Exception {
context.checking(new Expectations() {{
oneOf(db).getIdentities(txn);
will(returnValue(singletonList(identityWithoutKeys)));
oneOf(crypto).generateAgreementKeyPair();
will(returnValue(handshakeKeyPair));
oneOf(handshakePublicKey).getEncoded();
will(returnValue(handshakePublicKeyBytes));
oneOf(handshakePrivateKey).getEncoded();
will(returnValue(handshakePrivateKeyBytes));
oneOf(db).setHandshakeKeyPair(txn, localAuthor.getId(),
handshakePublicKeyBytes, handshakePrivateKeyBytes);
}});
identityManager.registerLocalAuthor(localAuthor);
identityManager.onDatabaseOpened(txn);
}
@Test
public void testOpenDatabaseNoHandshakeKeysGenerated() throws Exception {
context.checking(new Expectations() {{
oneOf(db).getIdentities(txn);
will(returnValue(singletonList(identityWithKeys)));
}});
identityManager.onDatabaseOpened(txn);
}
@Test
public void testGetLocalAuthorIdentityRegistered() throws DbException {
identityManager.registerIdentity(identityWithKeys);
assertEquals(localAuthor, identityManager.getLocalAuthor());
identityManager.storeLocalAuthor();
}
@Test
public void testGetLocalAuthor() throws Exception {
public void testGetLocalAuthorHandshakeKeysGenerated() throws Exception {
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getLocalAuthors(txn);
will(returnValue(localAuthors));
oneOf(db).getIdentities(txn);
will(returnValue(singletonList(identityWithoutKeys)));
oneOf(crypto).generateAgreementKeyPair();
will(returnValue(handshakeKeyPair));
oneOf(handshakePublicKey).getEncoded();
will(returnValue(handshakePublicKeyBytes));
oneOf(handshakePrivateKey).getEncoded();
will(returnValue(handshakePrivateKeyBytes));
}});
assertEquals(localAuthor, identityManager.getLocalAuthor());
}
@Test
public void testGetCachedLocalAuthor() throws DbException {
identityManager.registerLocalAuthor(localAuthor);
public void testGetLocalAuthorNoHandshakeKeysGenerated() throws Exception {
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getIdentities(txn);
will(returnValue(singletonList(identityWithKeys)));
}});
assertEquals(localAuthor, identityManager.getLocalAuthor());
}

View File

@@ -0,0 +1,53 @@
package org.briarproject.bramble.lifecycle;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.LifecycleManager.OpenDatabaseHook;
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;
import org.junit.Before;
import org.junit.Test;
import java.util.concurrent.atomic.AtomicBoolean;
import static junit.framework.TestCase.assertTrue;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
import static org.junit.Assert.assertEquals;
public class LifecycleManagerImplTest extends BrambleMockTestCase {
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
private final EventBus eventBus = context.mock(EventBus.class);
private final SecretKey dbKey = getSecretKey();
private LifecycleManagerImpl lifecycleManager;
@Before
public void setUp() {
lifecycleManager = new LifecycleManagerImpl(db, eventBus);
}
@Test
public void testOpenDatabaseHooksAreCalledAtStartup() throws Exception {
Transaction txn = new Transaction(null, false);
AtomicBoolean called = new AtomicBoolean(false);
OpenDatabaseHook hook = transaction -> called.set(true);
context.checking(new DbExpectations() {{
oneOf(db).open(dbKey, lifecycleManager);
will(returnValue(false));
oneOf(db).transaction(with(false), withDbRunnable(txn));
allowing(eventBus).broadcast(with(any(LifecycleEvent.class)));
}});
lifecycleManager.registerOpenDatabaseHook(hook);
assertEquals(SUCCESS, lifecycleManager.startServices(dbKey));
assertTrue(called.get());
}
}

View File

@@ -115,7 +115,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
1, true, true);
TransportPropertyManagerImpl t = createInstance();
t.createLocalState(txn);
t.onDatabaseOpened(txn);
}
@Test
@@ -129,7 +129,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
}});
TransportPropertyManagerImpl t = createInstance();
t.createLocalState(txn);
t.onDatabaseOpened(txn);
}
@Test

View File

@@ -6,7 +6,6 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Client;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@@ -32,7 +31,7 @@ public class TestLifecycleModule {
}
@Override
public void registerClient(Client c) {
public void registerOpenDatabaseHook(OpenDatabaseHook hook) {
}
@Override

View File

@@ -83,7 +83,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
expectAddingContact();
ClientVersioningManagerImpl c = createInstance();
c.createLocalState(txn);
c.onDatabaseOpened(txn);
}
@Test
@@ -95,7 +95,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
}});
ClientVersioningManagerImpl c = createInstance();
c.createLocalState(txn);
c.onDatabaseOpened(txn);
}
@Test