From 8283760e8ae6e8d212fc23ebf683673ba8fb6e6e Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 20 Jul 2018 13:55:30 +0100 Subject: [PATCH 01/18] Move local author creation into IdentityManager. --- .../bramble/api/contact/ContactManager.java | 2 +- .../bramble/api/db/DatabaseConfig.java | 5 -- .../bramble/api/identity/IdentityManager.java | 28 ++++++++--- .../api/lifecycle/LifecycleManager.java | 15 +++--- .../bramble/api/sync/ValidationManager.java | 5 +- .../versioning/ClientVersioningManager.java | 2 +- .../bramble/identity/IdentityManagerImpl.java | 43 +++++++++++++--- .../lifecycle/LifecycleManagerImpl.java | 34 +------------ .../bramble/lifecycle/LifecycleModule.java | 13 ++--- .../identity/IdentityManagerImplTest.java | 49 ++++++++++++++++--- .../bramble/test/TestDatabaseConfig.java | 10 ---- .../bramble/test/TestLifecycleModule.java | 9 ++-- .../briar/android/AndroidDatabaseConfig.java | 17 ------- .../briar/android/BriarService.java | 3 +- .../android/login/SetupControllerImpl.java | 15 ++++-- .../login/SetupControllerImplTest.java | 24 ++++++--- .../feed/FeedManagerIntegrationTest.java | 8 ++- .../FeedManagerIntegrationTestComponent.java | 3 ++ .../SimplexMessagingIntegrationTest.java | 16 +++--- .../briar/test/BriarIntegrationTest.java | 19 ++++--- 20 files changed, 177 insertions(+), 143 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java index 1f9daf48a..589fa53c2 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java @@ -16,7 +16,7 @@ public interface ContactManager { /** * Registers a hook to be called whenever a contact is added or removed. * This method should be called before - * {@link LifecycleManager#startServices(String)}. + * {@link LifecycleManager#startServices()}. */ void registerContactHook(ContactHook hook); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java index 0be85eba9..e431c15f2 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java @@ -21,10 +21,5 @@ public interface DatabaseConfig { @Nullable SecretKey getEncryptionKey(); - void setLocalAuthorName(String nickname); - - @Nullable - String getLocalAuthorName(); - long getMaxSize(); } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/identity/IdentityManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/identity/IdentityManager.java index bb584fec4..8160eb06d 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/identity/IdentityManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/identity/IdentityManager.java @@ -1,5 +1,6 @@ package org.briarproject.bramble.api.identity; +import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.identity.Author.Status; @@ -9,29 +10,40 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; public interface IdentityManager { /** - * Stores the local pseudonym. + * Creates a local identity with the given name. */ - void registerLocalAuthor(LocalAuthor a) throws DbException; + @CryptoExecutor + LocalAuthor createLocalAuthor(String name); /** - * Returns the cached main local identity, non-blocking, or loads it from - * the db, blocking + * Registers the given local identity with the manager. The identity is + * not stored until {@link #storeLocalAuthor()} is called. + */ + void registerLocalAuthor(LocalAuthor a); + + /** + * Stores the local identity registered with + * {@link #registerLocalAuthor(LocalAuthor)}, if any. + */ + void storeLocalAuthor() throws DbException; + + /** + * Returns the cached local identity or loads it from the database. */ LocalAuthor getLocalAuthor() throws DbException; /** - * Returns the cached main local identity, non-blocking, or loads it from - * the db, blocking, within the given Transaction. + * Returns the cached local identity or loads it from the database. */ LocalAuthor getLocalAuthor(Transaction txn) throws DbException; /** - * Returns the trust-level status of the author + * Returns the {@link Status} of the given author. */ Status getAuthorStatus(AuthorId a) throws DbException; /** - * Returns the trust-level status of the author + * Returns the {@link Status} of the given author. */ Status getAuthorStatus(Transaction txn, AuthorId a) throws DbException; diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java index d3cd1bc24..c54910b62 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java @@ -6,8 +6,6 @@ import org.briarproject.bramble.api.sync.Client; import java.util.concurrent.ExecutorService; -import javax.annotation.Nullable; - /** * Manages the lifecycle of the app, starting {@link Client Clients}, starting * and stopping {@link Service Services}, shutting down @@ -18,7 +16,7 @@ import javax.annotation.Nullable; public interface LifecycleManager { /** - * The result of calling {@link #startServices(String)}. + * The result of calling {@link #startServices()}. */ enum StartResult { ALREADY_RUNNING, @@ -44,28 +42,27 @@ public interface LifecycleManager { /** * Registers a {@link Service} to be started and stopped. This method - * should be called before {@link #startServices(String)}. + * should be called before {@link #startServices()}. */ void registerService(Service s); /** * Registers a {@link Client} to be started. This method should be called - * before {@link #startServices(String)}. + * before {@link #startServices()}. */ void registerClient(Client c); /** * Registers an {@link ExecutorService} to be shut down. This method - * should be called before {@link #startServices(String)}. + * should be called before {@link #startServices()}. */ void registerForShutdown(ExecutorService e); /** - * Opens the {@link DatabaseComponent}, optionally creates a local author - * with the provided nickname, and starts any registered + * Opens the {@link DatabaseComponent} and starts any registered * {@link Client Clients} and {@link Service Services}. */ - StartResult startServices(@Nullable String nickname); + StartResult startServices(); /** * Stops any registered {@link Service Services}, shuts down any diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/ValidationManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/ValidationManager.java index 1718cac81..5fe103ce8 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/ValidationManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/ValidationManager.java @@ -35,7 +35,7 @@ public interface ValidationManager { /** * Registers the message validator for the given client. This method - * should be called before {@link LifecycleManager#startServices(String)}. + * should be called before {@link LifecycleManager#startServices()}. */ void registerMessageValidator(ClientId c, int majorVersion, MessageValidator v); @@ -43,8 +43,7 @@ public interface ValidationManager { /** * Registers the incoming message hook for the given client. The hook will * be called once for each incoming message that passes validation. This - * method should be called before - * {@link LifecycleManager#startServices(String)}. + * method should be called before {@link LifecycleManager#startServices()}. */ void registerIncomingMessageHook(ClientId c, int majorVersion, IncomingMessageHook hook); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/versioning/ClientVersioningManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/versioning/ClientVersioningManager.java index 0cb2fc478..f2e98ea2c 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/versioning/ClientVersioningManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/versioning/ClientVersioningManager.java @@ -25,7 +25,7 @@ public interface ClientVersioningManager { /** * Registers a client that will be advertised to contacts. The hook will * be called when the visibility of the client changes. This method should - * be called before {@link LifecycleManager#startServices(String)}. + * be called before {@link LifecycleManager#startServices()}. */ void registerClient(ClientId clientId, int majorVersion, int minorVersion, ClientVersioningHook hook); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/identity/IdentityManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/identity/IdentityManagerImpl.java index 11e8220c9..44bf94550 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/identity/IdentityManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/identity/IdentityManagerImpl.java @@ -1,10 +1,13 @@ package org.briarproject.bramble.identity; import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.crypto.CryptoComponent; +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.Author.Status; +import org.briarproject.bramble.api.identity.AuthorFactory; import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.LocalAuthor; @@ -21,6 +24,8 @@ import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES; import static org.briarproject.bramble.api.identity.Author.Status.UNKNOWN; import static org.briarproject.bramble.api.identity.Author.Status.UNVERIFIED; import static org.briarproject.bramble.api.identity.Author.Status.VERIFIED; +import static org.briarproject.bramble.util.LogUtils.logDuration; +import static org.briarproject.bramble.util.LogUtils.now; @ThreadSafe @NotNullByDefault @@ -30,25 +35,51 @@ class IdentityManagerImpl implements IdentityManager { Logger.getLogger(IdentityManagerImpl.class.getName()); private final DatabaseComponent db; + private final CryptoComponent crypto; + private final AuthorFactory authorFactory; // The local author is immutable so we can cache it @Nullable private volatile LocalAuthor cachedAuthor; @Inject - IdentityManagerImpl(DatabaseComponent db) { + IdentityManagerImpl(DatabaseComponent db, CryptoComponent crypto, + AuthorFactory authorFactory) { this.db = db; + this.crypto = crypto; + this.authorFactory = authorFactory; } @Override - public void registerLocalAuthor(LocalAuthor localAuthor) - throws DbException { + public LocalAuthor createLocalAuthor(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; + } + + @Override + public void registerLocalAuthor(LocalAuthor a) { + cachedAuthor = a; + LOG.info("Local author registered"); + } + + @Override + public void storeLocalAuthor() throws DbException { + LocalAuthor cached = cachedAuthor; + if (cached == null) { + LOG.info("No local author to store"); + return; + } Transaction txn = db.startTransaction(false); try { - db.addLocalAuthor(txn, localAuthor); + db.addLocalAuthor(txn, cached); db.commitTransaction(txn); - cachedAuthor = localAuthor; - LOG.info("Local author registered"); + LOG.info("Local author stored"); } finally { db.endTransaction(txn); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java index 68c694189..b99ab31e1 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java @@ -1,7 +1,5 @@ package org.briarproject.bramble.lifecycle; -import org.briarproject.bramble.api.crypto.CryptoComponent; -import org.briarproject.bramble.api.crypto.KeyPair; import org.briarproject.bramble.api.db.DataTooNewException; import org.briarproject.bramble.api.db.DataTooOldException; import org.briarproject.bramble.api.db.DatabaseComponent; @@ -9,9 +7,7 @@ import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.MigrationListener; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.event.EventBus; -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; import org.briarproject.bramble.api.lifecycle.Service; import org.briarproject.bramble.api.lifecycle.ServiceException; @@ -26,7 +22,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Semaphore; import java.util.logging.Logger; -import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; import javax.inject.Inject; @@ -60,8 +55,6 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener { private final List services; private final List clients; private final List executors; - private final CryptoComponent crypto; - private final AuthorFactory authorFactory; private final IdentityManager identityManager; private final Semaphore startStopSemaphore = new Semaphore(1); private final CountDownLatch dbLatch = new CountDownLatch(1); @@ -72,12 +65,9 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener { @Inject LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus, - CryptoComponent crypto, AuthorFactory authorFactory, IdentityManager identityManager) { this.db = db; this.eventBus = eventBus; - this.crypto = crypto; - this.authorFactory = authorFactory; this.identityManager = identityManager; services = new CopyOnWriteArrayList<>(); clients = new CopyOnWriteArrayList<>(); @@ -104,25 +94,8 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener { executors.add(e); } - private LocalAuthor createLocalAuthor(String nickname) { - long start = now(); - KeyPair keyPair = crypto.generateSignatureKeyPair(); - byte[] publicKey = keyPair.getPublic().getEncoded(); - byte[] privateKey = keyPair.getPrivate().getEncoded(); - LocalAuthor localAuthor = authorFactory - .createLocalAuthor(nickname, publicKey, privateKey); - logDuration(LOG, "Creating local author", start); - return localAuthor; - } - - private void registerLocalAuthor(LocalAuthor author) throws DbException { - long start = now(); - identityManager.registerLocalAuthor(author); - logDuration(LOG, "Registering local author", start); - } - @Override - public StartResult startServices(@Nullable String nickname) { + public StartResult startServices() { if (!startStopSemaphore.tryAcquire()) { LOG.info("Already starting or stopping"); return ALREADY_RUNNING; @@ -134,10 +107,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener { boolean reopened = db.open(this); if (reopened) logDuration(LOG, "Reopening database", start); else logDuration(LOG, "Creating database", start); - - if (nickname != null) { - registerLocalAuthor(createLocalAuthor(nickname)); - } + identityManager.storeLocalAuthor(); state = STARTING_SERVICES; dbLatch.countDown(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleModule.java b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleModule.java index 8fcf789ed..43db266ef 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleModule.java @@ -1,10 +1,5 @@ package org.briarproject.bramble.lifecycle; -import org.briarproject.bramble.api.crypto.CryptoComponent; -import org.briarproject.bramble.api.db.DatabaseComponent; -import org.briarproject.bramble.api.event.EventBus; -import org.briarproject.bramble.api.identity.AuthorFactory; -import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.ShutdownManager; @@ -54,11 +49,9 @@ public class LifecycleModule { @Provides @Singleton - LifecycleManager provideLifecycleManager(DatabaseComponent db, - EventBus eventBus, CryptoComponent crypto, - AuthorFactory authorFactory, IdentityManager identityManager) { - return new LifecycleManagerImpl(db, eventBus, crypto, authorFactory, - identityManager); + LifecycleManager provideLifecycleManager( + LifecycleManagerImpl lifecycleManager) { + return lifecycleManager; } @Provides diff --git a/bramble-core/src/test/java/org/briarproject/bramble/identity/IdentityManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/identity/IdentityManagerImplTest.java index e24499ba7..2926cd3f3 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/identity/IdentityManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/identity/IdentityManagerImplTest.java @@ -2,15 +2,21 @@ package org.briarproject.bramble.identity; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.crypto.KeyPair; +import org.briarproject.bramble.api.crypto.PrivateKey; +import org.briarproject.bramble.api.crypto.PublicKey; 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.Author; +import org.briarproject.bramble.api.identity.AuthorFactory; import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.test.BrambleMockTestCase; import org.jmock.Expectations; +import org.junit.Before; import org.junit.Test; import java.util.ArrayList; @@ -27,24 +33,48 @@ import static org.junit.Assert.assertEquals; public class IdentityManagerImplTest extends BrambleMockTestCase { - private final IdentityManager identityManager; private final DatabaseComponent db = context.mock(DatabaseComponent.class); + 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 Transaction txn = new Transaction(null, false); private final LocalAuthor localAuthor = getLocalAuthor(); private final Collection 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; - public IdentityManagerImplTest() { - identityManager = new IdentityManagerImpl(db); + @Before + public void setUp() { + identityManager = new IdentityManagerImpl(db, crypto, authorFactory); } @Test - public void testRegisterLocalAuthor() throws DbException { - expectRegisterLocalAuthor(); - identityManager.registerLocalAuthor(localAuthor); + public void testCreateLocalAuthor() { + 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)); + }}); + + assertEquals(localAuthor, + identityManager.createLocalAuthor(authorName)); } - private void expectRegisterLocalAuthor() throws DbException { + @Test + public void testRegisterAndStoreLocalAuthor() throws DbException { context.checking(new Expectations() {{ oneOf(db).startTransaction(false); will(returnValue(txn)); @@ -52,6 +82,10 @@ public class IdentityManagerImplTest extends BrambleMockTestCase { oneOf(db).commitTransaction(txn); oneOf(db).endTransaction(txn); }}); + + identityManager.registerLocalAuthor(localAuthor); + assertEquals(localAuthor, identityManager.getLocalAuthor()); + identityManager.storeLocalAuthor(); } @Test @@ -69,7 +103,6 @@ public class IdentityManagerImplTest extends BrambleMockTestCase { @Test public void testGetCachedLocalAuthor() throws DbException { - expectRegisterLocalAuthor(); identityManager.registerLocalAuthor(localAuthor); assertEquals(localAuthor, identityManager.getLocalAuthor()); } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/test/TestDatabaseConfig.java b/bramble-core/src/test/java/org/briarproject/bramble/test/TestDatabaseConfig.java index a830795f3..7e5ad34e7 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/test/TestDatabaseConfig.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/test/TestDatabaseConfig.java @@ -46,16 +46,6 @@ public class TestDatabaseConfig implements DatabaseConfig { return key; } - @Override - public void setLocalAuthorName(String nickname) { - - } - - @Override - public String getLocalAuthorName() { - return null; - } - @Override public long getMaxSize() { return maxSize; diff --git a/bramble-core/src/test/java/org/briarproject/bramble/test/TestLifecycleModule.java b/bramble-core/src/test/java/org/briarproject/bramble/test/TestLifecycleModule.java index 15943adc2..01d97c52b 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/test/TestLifecycleModule.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/test/TestLifecycleModule.java @@ -11,7 +11,6 @@ import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import javax.annotation.Nullable; import javax.inject.Singleton; import dagger.Module; @@ -40,7 +39,7 @@ public class TestLifecycleModule { } @Override - public StartResult startServices(@Nullable String nickname) { + public StartResult startServices() { return StartResult.SUCCESS; } @@ -49,15 +48,15 @@ public class TestLifecycleModule { } @Override - public void waitForDatabase() throws InterruptedException { + public void waitForDatabase() { } @Override - public void waitForStartup() throws InterruptedException { + public void waitForStartup() { } @Override - public void waitForShutdown() throws InterruptedException { + public void waitForShutdown() { } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidDatabaseConfig.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidDatabaseConfig.java index e92a356ee..1f21acdb0 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidDatabaseConfig.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidDatabaseConfig.java @@ -21,8 +21,6 @@ class AndroidDatabaseConfig implements DatabaseConfig { @Nullable private volatile SecretKey key = null; - @Nullable - private volatile String nickname = null; AndroidDatabaseConfig(File dbDir, File keyDir) { this.dbDir = dbDir; @@ -70,21 +68,6 @@ class AndroidDatabaseConfig implements DatabaseConfig { this.key = key; } - @Override - public void setLocalAuthorName(String nickname) { - LOG.info("Setting local author name"); - this.nickname = nickname; - } - - @Override - @Nullable - public String getLocalAuthorName() { - String nickname = this.nickname; - if (LOG.isLoggable(INFO)) - LOG.info("Local author name has been set: " + (nickname != null)); - return nickname; - } - @Override @Nullable public SecretKey getEncryptionKey() { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java index 523935278..f40d2a42b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java @@ -141,8 +141,7 @@ public class BriarService extends Service { nm.cancel(REMINDER_NOTIFICATION_ID); // Start the services in a background thread new Thread(() -> { - String nickname = databaseConfig.getLocalAuthorName(); - StartResult result = lifecycleManager.startServices(nickname); + StartResult result = lifecycleManager.startServices(); if (result == SUCCESS) { started = true; } else if (result == ALREADY_RUNNING) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java index 3923cce4a..4c56553ba 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java @@ -8,6 +8,8 @@ import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.android.controller.handler.ResultHandler; import org.briarproject.briar.android.controller.handler.UiResultHandler; @@ -24,6 +26,8 @@ public class SetupControllerImpl extends PasswordControllerImpl private static final Logger LOG = Logger.getLogger(SetupControllerImpl.class.getName()); + private final IdentityManager identityManager; + @Nullable private volatile SetupActivity setupActivity; @@ -31,9 +35,11 @@ public class SetupControllerImpl extends PasswordControllerImpl SetupControllerImpl(SharedPreferences briarPrefs, DatabaseConfig databaseConfig, @CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto, - PasswordStrengthEstimator strengthEstimator) { + PasswordStrengthEstimator strengthEstimator, + IdentityManager identityManager) { super(briarPrefs, databaseConfig, cryptoExecutor, crypto, strengthEstimator); + this.identityManager = identityManager; } @Override @@ -102,13 +108,14 @@ public class SetupControllerImpl extends PasswordControllerImpl if (password == null) throw new IllegalStateException(); cryptoExecutor.execute(() -> { LOG.info("Creating account"); - databaseConfig.setLocalAuthorName(authorName); + LocalAuthor localAuthor = + identityManager.createLocalAuthor(authorName); + identityManager.registerLocalAuthor(localAuthor); SecretKey key = crypto.generateSecretKey(); - databaseConfig.setEncryptionKey(key); String hex = encryptDatabaseKey(key, password); storeEncryptedDatabaseKey(hex); + databaseConfig.setEncryptionKey(key); resultHandler.onResult(null); }); } - } diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java index b0df4cde8..f95aab6dd 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java @@ -7,6 +7,8 @@ import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.ImmediateExecutor; import org.jmock.Expectations; @@ -23,6 +25,7 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; +import static org.briarproject.bramble.test.TestUtils.getLocalAuthor; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getTestDirectory; @@ -39,12 +42,15 @@ public class SetupControllerImplTest extends BrambleMockTestCase { private final CryptoComponent crypto = context.mock(CryptoComponent.class); private final PasswordStrengthEstimator estimator = context.mock(PasswordStrengthEstimator.class); + private final IdentityManager identityManager = + context.mock(IdentityManager.class); private final SetupActivity setupActivity; private final Executor cryptoExecutor = new ImmediateExecutor(); private final String authorName = getRandomString(MAX_AUTHOR_NAME_LENGTH); private final String password = "some.strong.pass"; + private final LocalAuthor localAuthor = getLocalAuthor(); private final byte[] encryptedKey = getRandomBytes(123); private final SecretKey key = getSecretKey(); private final File testDir = getTestDirectory(); @@ -74,25 +80,29 @@ public class SetupControllerImplTest extends BrambleMockTestCase { will(returnValue(authorName)); oneOf(setupActivity).getPassword(); will(returnValue(password)); + // Create and register the local author + oneOf(identityManager).createLocalAuthor(authorName); + will(returnValue(localAuthor)); + oneOf(identityManager).registerLocalAuthor(localAuthor); // Generate a database key oneOf(crypto).generateSecretKey(); will(returnValue(key)); - // Attach the author name and database key to the database config - oneOf(databaseConfig).setLocalAuthorName(authorName); - oneOf(databaseConfig).setEncryptionKey(key); // Encrypt the key with the password oneOf(crypto).encryptWithPassword(key.getBytes(), password); will(returnValue(encryptedKey)); // Store the encrypted key allowing(databaseConfig).getDatabaseKeyDirectory(); will(returnValue(keyDir)); + // Attach the database key to the database config + oneOf(databaseConfig).setEncryptionKey(key); }}); assertFalse(keyFile.exists()); assertFalse(keyBackupFile.exists()); SetupControllerImpl s = new SetupControllerImpl(briarPrefs, - databaseConfig, cryptoExecutor, crypto, estimator); + databaseConfig, cryptoExecutor, crypto, estimator, + identityManager); s.setSetupActivity(setupActivity); AtomicBoolean called = new AtomicBoolean(false); @@ -103,8 +113,10 @@ public class SetupControllerImplTest extends BrambleMockTestCase { assertTrue(keyFile.exists()); assertTrue(keyBackupFile.exists()); - assertEquals(toHexString(encryptedKey), loadDatabaseKey(keyFile)); - assertEquals(toHexString(encryptedKey), loadDatabaseKey(keyBackupFile)); + assertEquals(toHexString(encryptedKey), + loadDatabaseKey(keyFile)); + assertEquals(toHexString(encryptedKey), + loadDatabaseKey(keyBackupFile)); } @After diff --git a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java index 24c7334e7..fec963b33 100644 --- a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java @@ -1,5 +1,7 @@ package org.briarproject.briar.feed; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.contact.ContactModule; import org.briarproject.bramble.crypto.CryptoExecutorModule; @@ -47,8 +49,12 @@ public class FeedManagerIntegrationTest extends BriarTestCase { component.inject(this); injectEagerSingletons(component); + IdentityManager identityManager = component.getIdentityManager(); + LocalAuthor localAuthor = identityManager.createLocalAuthor("feedTest"); + identityManager.registerLocalAuthor(localAuthor); + lifecycleManager = component.getLifecycleManager(); - lifecycleManager.startServices("feedTest"); + lifecycleManager.startServices(); lifecycleManager.waitForStartup(); feedManager = component.getFeedManager(); diff --git a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java index 76445fe03..685eedacb 100644 --- a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java @@ -1,5 +1,6 @@ package org.briarproject.briar.feed; +import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.client.ClientModule; import org.briarproject.bramble.contact.ContactModule; @@ -76,6 +77,8 @@ interface FeedManagerIntegrationTestComponent { void inject(VersioningModule.EagerSingletons init); + IdentityManager getIdentityManager(); + LifecycleManager getLifecycleManager(); FeedManager getFeedManager(); diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java index 1007afe5e..5c8b0ca65 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java @@ -44,7 +44,6 @@ import java.io.InputStream; import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; import static org.briarproject.bramble.test.TestPluginConfigModule.MAX_LATENCY; import static org.briarproject.bramble.test.TestPluginConfigModule.TRANSPORT_ID; -import static org.briarproject.bramble.test.TestUtils.getLocalAuthor; import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getTestDirectory; import static org.junit.Assert.assertEquals; @@ -58,8 +57,6 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { private final File bobDir = new File(testDir, "bob"); private final SecretKey master = getSecretKey(); private final long timestamp = System.currentTimeMillis(); - private final LocalAuthor aliceAuthor = getLocalAuthor(); - private final LocalAuthor bobAuthor = getLocalAuthor(); private SimplexMessagingIntegrationTestComponent alice, bob; @@ -76,6 +73,11 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { @Test public void testWriteAndRead() throws Exception { + // Create the identities + LocalAuthor aliceAuthor = + alice.getIdentityManager().createLocalAuthor("Alice"); + LocalAuthor bobAuthor = + bob.getIdentityManager().createLocalAuthor("Bob"); // Set up the devices and get the contact IDs ContactId bobId = setUp(alice, aliceAuthor, bobAuthor, true); ContactId aliceId = setUp(bob, bobAuthor, aliceAuthor, false); @@ -98,13 +100,13 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { private ContactId setUp(SimplexMessagingIntegrationTestComponent device, LocalAuthor local, Author remote, boolean alice) throws Exception { - // Start the lifecycle manager - LifecycleManager lifecycleManager = device.getLifecycleManager(); - lifecycleManager.startServices(null); - lifecycleManager.waitForStartup(); // Add an identity for the user IdentityManager identityManager = device.getIdentityManager(); identityManager.registerLocalAuthor(local); + // Start the lifecycle manager + LifecycleManager lifecycleManager = device.getLifecycleManager(); + lifecycleManager.startServices(); + lifecycleManager.waitForStartup(); // Add the other user as a contact ContactManager contactManager = device.getContactManager(); return contactManager.addContact(remote, local.getId(), master, diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java index 481a57486..9f2ecec4a 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java @@ -160,8 +160,8 @@ public abstract class BriarIntegrationTest Date: Fri, 20 Jul 2018 15:08:53 +0100 Subject: [PATCH 02/18] Create minimal AccountManager interface. --- .../bramble/api/account/AccountManager.java | 6 ++++++ .../bramble/BrambleCoreModule.java | 2 ++ .../bramble/account/AccountManagerImpl.java | 21 +++++++++++++++++++ .../bramble/account/AccountModule.java | 18 ++++++++++++++++ .../briar/android/AndroidComponent.java | 3 +++ .../briar/android/BriarService.java | 11 +++++----- .../briar/android/activity/BriarActivity.java | 4 ++-- .../android/controller/BriarController.java | 2 +- .../controller/BriarControllerImpl.java | 15 +++++++------ .../controller/ConfigControllerImpl.java | 7 +++++-- .../briar/android/login/PasswordActivity.java | 2 +- .../android/login/PasswordControllerImpl.java | 5 +++-- .../android/login/SetupControllerImpl.java | 7 ++++--- .../controller/ConfigControllerImplTest.java | 15 +++++++------ .../android/forum/TestForumActivity.java | 2 +- .../login/PasswordControllerImplTest.java | 9 ++++++-- .../login/SetupControllerImplTest.java | 7 +++++-- .../test/BriarIntegrationTestComponent.java | 2 ++ 18 files changed, 103 insertions(+), 35 deletions(-) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java create mode 100644 bramble-core/src/main/java/org/briarproject/bramble/account/AccountModule.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java new file mode 100644 index 000000000..4aa4fb2b5 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java @@ -0,0 +1,6 @@ +package org.briarproject.bramble.api.account; + +public interface AccountManager { + + boolean hasDatabaseKey(); +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/BrambleCoreModule.java b/bramble-core/src/main/java/org/briarproject/bramble/BrambleCoreModule.java index 07bc14eea..d817c6d57 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/BrambleCoreModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/BrambleCoreModule.java @@ -1,5 +1,6 @@ package org.briarproject.bramble; +import org.briarproject.bramble.account.AccountModule; import org.briarproject.bramble.client.ClientModule; import org.briarproject.bramble.contact.ContactModule; import org.briarproject.bramble.crypto.CryptoExecutorModule; @@ -26,6 +27,7 @@ import org.briarproject.bramble.versioning.VersioningModule; import dagger.Module; @Module(includes = { + AccountModule.class, ClientModule.class, ContactModule.class, CryptoModule.class, diff --git a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java new file mode 100644 index 000000000..dd4df479a --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java @@ -0,0 +1,21 @@ +package org.briarproject.bramble.account; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.db.DatabaseConfig; + +import javax.inject.Inject; + +class AccountManagerImpl implements AccountManager { + + private final DatabaseConfig databaseConfig; + + @Inject + AccountManagerImpl(DatabaseConfig databaseConfig) { + this.databaseConfig = databaseConfig; + } + + @Override + public boolean hasDatabaseKey() { + return databaseConfig.getEncryptionKey() != null; + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountModule.java b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountModule.java new file mode 100644 index 000000000..e8220176a --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountModule.java @@ -0,0 +1,18 @@ +package org.briarproject.bramble.account; + +import org.briarproject.bramble.api.account.AccountManager; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class AccountModule { + + @Provides + @Singleton + AccountManager provideAccountManager(AccountManagerImpl accountManager) { + return accountManager; + } +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java index 087aa5ea0..8935cfb7f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java @@ -5,6 +5,7 @@ import android.content.SharedPreferences; import org.briarproject.bramble.BrambleAndroidModule; import org.briarproject.bramble.BrambleCoreEagerSingletons; import org.briarproject.bramble.BrambleCoreModule; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.contact.ContactExchangeTask; import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.crypto.CryptoComponent; @@ -151,6 +152,8 @@ public interface AndroidComponent @IoExecutor Executor ioExecutor(); + AccountManager accountManager(); + void inject(SignInReminderReceiver briarService); void inject(BriarService briarService); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java index f40d2a42b..980e6cdfc 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java @@ -17,7 +17,7 @@ import android.os.IBinder; import android.support.v4.app.NotificationCompat; import android.support.v4.content.ContextCompat; -import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult; import org.briarproject.bramble.api.system.AndroidExecutor; @@ -75,12 +75,13 @@ public class BriarService extends Service { private BroadcastReceiver receiver = null; @Inject - protected DatabaseConfig databaseConfig; + AccountManager accountManager; + // Fields that are accessed from background threads must be volatile @Inject - protected volatile LifecycleManager lifecycleManager; + volatile LifecycleManager lifecycleManager; @Inject - protected volatile AndroidExecutor androidExecutor; + volatile AndroidExecutor androidExecutor; private volatile boolean started = false; @Override @@ -96,7 +97,7 @@ public class BriarService extends Service { stopSelf(); return; } - if (databaseConfig.getEncryptionKey() == null) { + if (!accountManager.hasDatabaseKey()) { LOG.info("No database key"); stopSelf(); return; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java index 3d2d8361c..cf71839f9 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java @@ -61,7 +61,7 @@ public abstract class BriarActivity extends BaseActivity { @Override public void onStart() { super.onStart(); - if (!briarController.hasEncryptionKey() && !isFinishing()) { + if (!briarController.accountSignedIn() && !isFinishing()) { Intent i = new Intent(this, PasswordActivity.class); startActivityForResult(i, REQUEST_PASSWORD); } else if (SDK_INT >= 23) { @@ -138,7 +138,7 @@ public abstract class BriarActivity extends BaseActivity { } protected void signOut(boolean removeFromRecentApps) { - if (briarController.hasEncryptionKey()) { + if (briarController.accountSignedIn()) { // Don't use UiResultHandler because we want the result even if // this activity has been destroyed briarController.signOut(result -> runOnUiThread( diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarController.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarController.java index 350faeaba..e4e60c692 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarController.java @@ -6,7 +6,7 @@ public interface BriarController extends ActivityLifecycleController { void startAndBindService(); - boolean hasEncryptionKey(); + boolean accountSignedIn(); /** * Returns true via the handler when the app has dozed diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java index a668a450d..1271f4d21 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java @@ -5,7 +5,7 @@ import android.content.Intent; import android.os.IBinder; import android.support.annotation.CallSuper; -import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.settings.Settings; @@ -33,8 +33,7 @@ public class BriarControllerImpl implements BriarController { public static final String DOZE_ASK_AGAIN = "dozeAskAgain"; private final BriarServiceConnection serviceConnection; - private final DatabaseConfig databaseConfig; - @DatabaseExecutor + private final AccountManager accountManager; private final Executor databaseExecutor; private final SettingsManager settingsManager; private final DozeWatchdog dozeWatchdog; @@ -44,12 +43,12 @@ public class BriarControllerImpl implements BriarController { @Inject BriarControllerImpl(BriarServiceConnection serviceConnection, - DatabaseConfig databaseConfig, + AccountManager accountManager, @DatabaseExecutor Executor databaseExecutor, SettingsManager settingsManager, DozeWatchdog dozeWatchdog, Activity activity) { this.serviceConnection = serviceConnection; - this.databaseConfig = databaseConfig; + this.accountManager = accountManager; this.databaseExecutor = databaseExecutor; this.settingsManager = settingsManager; this.dozeWatchdog = dozeWatchdog; @@ -59,7 +58,7 @@ public class BriarControllerImpl implements BriarController { @Override @CallSuper public void onActivityCreate(Activity activity) { - if (databaseConfig.getEncryptionKey() != null) startAndBindService(); + if (accountManager.hasDatabaseKey()) startAndBindService(); } @Override @@ -84,8 +83,8 @@ public class BriarControllerImpl implements BriarController { } @Override - public boolean hasEncryptionKey() { - return databaseConfig.getEncryptionKey() != null; + public boolean accountSignedIn() { + return accountManager.hasDatabaseKey(); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java index 1e0bce3a2..cb0d2c3c3 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.support.v7.preference.PreferenceManager; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.util.AndroidUtils; @@ -34,12 +35,14 @@ public class ConfigControllerImpl implements ConfigController { private final SharedPreferences briarPrefs; private final File dbKeyFile, dbKeyBackupFile; + private final AccountManager accountManager; protected final DatabaseConfig databaseConfig; @Inject public ConfigControllerImpl(SharedPreferences briarPrefs, - DatabaseConfig databaseConfig) { + AccountManager accountManager, DatabaseConfig databaseConfig) { this.briarPrefs = briarPrefs; + this.accountManager = accountManager; this.databaseConfig = databaseConfig; File keyDir = databaseConfig.getDatabaseKeyDirectory(); dbKeyFile = new File(keyDir, DB_KEY_FILENAME); @@ -166,6 +169,6 @@ public class ConfigControllerImpl implements ConfigController { @Override public boolean accountSignedIn() { - return databaseConfig.getEncryptionKey() != null; + return accountManager.hasDatabaseKey(); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java index f4368dd9a..5504132b4 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java @@ -85,7 +85,7 @@ public class PasswordActivity extends BaseActivity { public void onStart() { super.onStart(); // If the user has already signed in, clean up this instance - if (briarController.hasEncryptionKey()) { + if (briarController.accountSignedIn()) { setResult(RESULT_OK); finish(); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java index 905797acc..ca9634502 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java @@ -2,6 +2,7 @@ package org.briarproject.briar.android.login; import android.content.SharedPreferences; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; @@ -33,10 +34,10 @@ public class PasswordControllerImpl extends ConfigControllerImpl @Inject PasswordControllerImpl(SharedPreferences briarPrefs, - DatabaseConfig databaseConfig, + AccountManager accountManager, DatabaseConfig databaseConfig, @CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto, PasswordStrengthEstimator strengthEstimator) { - super(briarPrefs, databaseConfig); + super(briarPrefs, accountManager, databaseConfig); this.cryptoExecutor = cryptoExecutor; this.crypto = crypto; this.strengthEstimator = strengthEstimator; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java index 4c56553ba..30d039849 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java @@ -3,6 +3,7 @@ package org.briarproject.briar.android.login; import android.content.SharedPreferences; import android.support.annotation.Nullable; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; @@ -33,12 +34,12 @@ public class SetupControllerImpl extends PasswordControllerImpl @Inject SetupControllerImpl(SharedPreferences briarPrefs, - DatabaseConfig databaseConfig, + AccountManager accountManager, DatabaseConfig databaseConfig, @CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto, PasswordStrengthEstimator strengthEstimator, IdentityManager identityManager) { - super(briarPrefs, databaseConfig, cryptoExecutor, crypto, - strengthEstimator); + super(briarPrefs, accountManager, databaseConfig, cryptoExecutor, + crypto, strengthEstimator); this.identityManager = identityManager; } diff --git a/briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java index 859792b3c..d8e4445c2 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java @@ -3,6 +3,7 @@ package org.briarproject.briar.android.controller; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.test.BrambleMockTestCase; import org.jmock.Expectations; @@ -26,6 +27,8 @@ public class ConfigControllerImplTest extends BrambleMockTestCase { private final SharedPreferences prefs = context.mock(SharedPreferences.class); + private final AccountManager accountManager = + context.mock(AccountManager.class); private final DatabaseConfig databaseConfig = context.mock(DatabaseConfig.class); private final Editor editor = context.mock(Editor.class); @@ -56,7 +59,7 @@ public class ConfigControllerImplTest extends BrambleMockTestCase { assertFalse(keyFile.exists()); assertFalse(keyBackupFile.exists()); - ConfigControllerImpl c = new ConfigControllerImpl(prefs, + ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager, databaseConfig); assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey()); @@ -85,7 +88,7 @@ public class ConfigControllerImplTest extends BrambleMockTestCase { assertFalse(keyBackupFile.exists()); assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); - ConfigControllerImpl c = new ConfigControllerImpl(prefs, + ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager, databaseConfig); assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey()); @@ -113,7 +116,7 @@ public class ConfigControllerImplTest extends BrambleMockTestCase { assertTrue(keyBackupFile.exists()); assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); - ConfigControllerImpl c = new ConfigControllerImpl(prefs, + ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager, databaseConfig); assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey()); @@ -135,7 +138,7 @@ public class ConfigControllerImplTest extends BrambleMockTestCase { assertFalse(keyFile.exists()); assertFalse(keyBackupFile.exists()); - ConfigControllerImpl c = new ConfigControllerImpl(prefs, + ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager, databaseConfig); assertNull(c.getEncryptedDatabaseKey()); @@ -160,7 +163,7 @@ public class ConfigControllerImplTest extends BrambleMockTestCase { assertFalse(keyBackupFile.exists()); assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyFile)); - ConfigController c = new ConfigControllerImpl(prefs, + ConfigController c = new ConfigControllerImpl(prefs, accountManager, databaseConfig); assertTrue(c.storeEncryptedDatabaseKey(encryptedKeyHex)); @@ -187,7 +190,7 @@ public class ConfigControllerImplTest extends BrambleMockTestCase { assertTrue(keyBackupFile.exists()); assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyBackupFile)); - ConfigController c = new ConfigControllerImpl(prefs, + ConfigController c = new ConfigControllerImpl(prefs, accountManager, databaseConfig); assertTrue(c.storeEncryptedDatabaseKey(encryptedKeyHex)); diff --git a/briar-android/src/test/java/org/briarproject/briar/android/forum/TestForumActivity.java b/briar-android/src/test/java/org/briarproject/briar/android/forum/TestForumActivity.java index 72b8d6644..7a04b4517 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/forum/TestForumActivity.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/forum/TestForumActivity.java @@ -45,7 +45,7 @@ public class TestForumActivity extends ForumActivity { protected BriarController provideBriarController( BriarControllerImpl briarController) { BriarController c = Mockito.mock(BriarController.class); - Mockito.when(c.hasEncryptionKey()).thenReturn(true); + Mockito.when(c.accountSignedIn()).thenReturn(true); return c; } diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java index 427dfa772..dcc2685b6 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java @@ -2,6 +2,7 @@ package org.briarproject.briar.android.login; import android.content.SharedPreferences; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.api.db.DatabaseConfig; @@ -30,6 +31,8 @@ public class PasswordControllerImplTest extends BrambleMockTestCase { private final SharedPreferences briarPrefs = context.mock(SharedPreferences.class); + private final AccountManager accountManager = + context.mock(AccountManager.class); private final DatabaseConfig databaseConfig = context.mock(DatabaseConfig.class); private final CryptoComponent crypto = context.mock(CryptoComponent.class); @@ -70,7 +73,8 @@ public class PasswordControllerImplTest extends BrambleMockTestCase { storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey)); PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs, - databaseConfig, cryptoExecutor, crypto, estimator); + accountManager, databaseConfig, cryptoExecutor, crypto, + estimator); AtomicBoolean capturedResult = new AtomicBoolean(false); p.changePassword(oldPassword, newPassword, capturedResult::set); @@ -104,7 +108,8 @@ public class PasswordControllerImplTest extends BrambleMockTestCase { storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey)); PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs, - databaseConfig, cryptoExecutor, crypto, estimator); + accountManager, databaseConfig, cryptoExecutor, crypto, + estimator); AtomicBoolean capturedResult = new AtomicBoolean(true); p.changePassword(oldPassword, newPassword, capturedResult::set); diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java index f95aab6dd..dd8825147 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java @@ -3,6 +3,7 @@ package org.briarproject.briar.android.login; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.api.crypto.SecretKey; @@ -37,6 +38,8 @@ public class SetupControllerImplTest extends BrambleMockTestCase { private final SharedPreferences briarPrefs = context.mock(SharedPreferences.class); + private final AccountManager accountManager = + context.mock(AccountManager.class); private final DatabaseConfig databaseConfig = context.mock(DatabaseConfig.class); private final CryptoComponent crypto = context.mock(CryptoComponent.class); @@ -101,8 +104,8 @@ public class SetupControllerImplTest extends BrambleMockTestCase { assertFalse(keyBackupFile.exists()); SetupControllerImpl s = new SetupControllerImpl(briarPrefs, - databaseConfig, cryptoExecutor, crypto, estimator, - identityManager); + accountManager, databaseConfig, cryptoExecutor, crypto, + estimator, identityManager); s.setSetupActivity(setupActivity); AtomicBoolean called = new AtomicBoolean(false); diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java index a3b74d4c2..d55b06d00 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java @@ -1,5 +1,6 @@ package org.briarproject.briar.test; +import org.briarproject.bramble.account.AccountModule; import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.db.DatabaseComponent; @@ -54,6 +55,7 @@ import dagger.Component; TestDatabaseModule.class, TestPluginConfigModule.class, TestSecureRandomModule.class, + AccountModule.class, BlogModule.class, BriarClientModule.class, ClientModule.class, From f9495b49d66d390c2cb520df91c529c68e90f2c3 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 23 Jul 2018 10:18:38 +0100 Subject: [PATCH 03/18] Move encrypted key, account deletion into AccountManager. --- .../bramble/api/account/AccountManager.java | 16 ++ .../bramble/api/db/DatabaseComponent.java | 10 +- .../bramble/api/db/DatabaseConfig.java | 8 - .../bramble/account/AccountManagerImpl.java | 121 ++++++++++++- .../org/briarproject/bramble/db/Database.java | 6 +- .../bramble/db/DatabaseComponentImpl.java | 5 +- .../briarproject/bramble/db/H2Database.java | 12 +- .../bramble/db/HyperSqlDatabase.java | 11 +- .../briarproject/bramble/db/JdbcDatabase.java | 2 +- .../lifecycle/LifecycleManagerImpl.java | 10 +- .../account/AccountManagerImplTest.java | 158 +++++++++++++++++ .../bramble/db/DatabaseComponentImplTest.java | 9 +- .../bramble/db/DatabaseMigrationTest.java | 33 ++-- .../db/DatabasePerformanceComparisonTest.java | 3 +- .../bramble/db/DatabaseTraceTest.java | 3 +- .../bramble/db/H2MigrationTest.java | 4 +- .../bramble/db/JdbcDatabaseTest.java | 8 +- .../db/SingleDatabasePerformanceTest.java | 3 +- .../bramble/test/TestDatabaseConfig.java | 12 -- .../briar/android/AndroidDatabaseConfig.java | 21 --- .../controller/ConfigControllerImpl.java | 95 +--------- .../android/login/PasswordControllerImpl.java | 2 +- .../android/login/SetupControllerImpl.java | 2 +- .../briar/android/TestDatabaseKeyUtils.java | 35 ---- .../controller/ConfigControllerImplTest.java | 167 +----------------- .../login/PasswordControllerImplTest.java | 58 ++---- .../login/SetupControllerImplTest.java | 43 +---- .../feed/FeedManagerIntegrationTest.java | 3 + .../FeedManagerIntegrationTestComponent.java | 5 + .../IntroductionIntegrationTestComponent.java | 2 + .../SimplexMessagingIntegrationTest.java | 2 + ...plexMessagingIntegrationTestComponent.java | 5 + .../briar/test/BriarIntegrationTest.java | 3 + .../test/BriarIntegrationTestComponent.java | 3 + 34 files changed, 418 insertions(+), 462 deletions(-) create mode 100644 bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java delete mode 100644 briar-android/src/test/java/org/briarproject/briar/android/TestDatabaseKeyUtils.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java index 4aa4fb2b5..e1efc91dc 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java @@ -1,6 +1,22 @@ package org.briarproject.bramble.api.account; +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.Nullable; + +@NotNullByDefault public interface AccountManager { boolean hasDatabaseKey(); + + @Nullable + SecretKey getDatabaseKey(); + + void setDatabaseKey(SecretKey k); + + @Nullable + String getEncryptedDatabaseKey(); + + boolean storeEncryptedDatabaseKey(String hex); } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java index 914b88a2e..f4161cee4 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.api.db; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.LocalAuthor; @@ -44,7 +45,8 @@ public interface DatabaseComponent { * @throws DataTooOldException if the data uses an older schema than the * current code and cannot be migrated */ - boolean open(@Nullable MigrationListener listener) throws DbException; + boolean open(SecretKey key, @Nullable MigrationListener listener) + throws DbException; /** * Waits for any open transactions to finish and closes the database. @@ -267,7 +269,7 @@ public interface DatabaseComponent { * Read-only. */ Collection getMessageIds(Transaction txn, GroupId g) - throws DbException; + throws DbException; /** * Returns the IDs of any messages that need to be validated. @@ -487,7 +489,7 @@ public interface DatabaseComponent { * Removes the given transport keys from the database. */ void removeTransportKeys(Transaction txn, TransportId t, KeySetId k) - throws DbException; + throws DbException; /** * Marks the given contact as verified. @@ -534,7 +536,7 @@ public interface DatabaseComponent { * Marks the given transport keys as usable for outgoing streams. */ void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k) - throws DbException; + throws DbException; /** * Stores the given transport keys, deleting any keys they have replaced. diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java index e431c15f2..a9a95c47a 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java @@ -1,12 +1,9 @@ package org.briarproject.bramble.api.db; -import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import java.io.File; -import javax.annotation.Nullable; - @NotNullByDefault public interface DatabaseConfig { @@ -16,10 +13,5 @@ public interface DatabaseConfig { File getDatabaseKeyDirectory(); - void setEncryptionKey(SecretKey key); - - @Nullable - SecretKey getEncryptionKey(); - long getMaxSize(); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java index dd4df479a..cbc813d71 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java @@ -1,21 +1,140 @@ package org.briarproject.bramble.account; import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.logging.Logger; + +import javax.annotation.Nullable; import javax.inject.Inject; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault class AccountManagerImpl implements AccountManager { + private static final Logger LOG = + Logger.getLogger(AccountManagerImpl.class.getName()); + + private static final String DB_KEY_FILENAME = "db.key"; + private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak"; + private final DatabaseConfig databaseConfig; + private final File dbKeyFile, dbKeyBackupFile; + + @Nullable + private volatile SecretKey databaseKey = null; @Inject AccountManagerImpl(DatabaseConfig databaseConfig) { this.databaseConfig = databaseConfig; + File keyDir = databaseConfig.getDatabaseKeyDirectory(); + dbKeyFile = new File(keyDir, DB_KEY_FILENAME); + dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME); } @Override public boolean hasDatabaseKey() { - return databaseConfig.getEncryptionKey() != null; + return databaseKey != null; + } + + @Override + @Nullable + public SecretKey getDatabaseKey() { + return databaseKey; + } + + @Override + public void setDatabaseKey(SecretKey k) { + databaseKey = k; + } + + @Override + @Nullable + public String getEncryptedDatabaseKey() { + String key = readDbKeyFromFile(dbKeyFile); + if (key == null) { + LOG.info("No database key in primary file"); + key = readDbKeyFromFile(dbKeyBackupFile); + if (key == null) LOG.info("No database key in backup file"); + else LOG.warning("Found database key in backup file"); + } else { + LOG.info("Found database key in primary file"); + } + return key; + } + + @Nullable + private String readDbKeyFromFile(File f) { + if (!f.exists()) { + LOG.info("Key file does not exist"); + return null; + } + try { + BufferedReader reader = new BufferedReader(new InputStreamReader( + new FileInputStream(f), "UTF-8")); + String key = reader.readLine(); + reader.close(); + return key; + } catch (IOException e) { + logException(LOG, WARNING, e); + return null; + } + } + + @Override + public boolean storeEncryptedDatabaseKey(String hex) { + LOG.info("Storing database key in file"); + // Create the directory if necessary + if (databaseConfig.getDatabaseKeyDirectory().mkdirs()) + LOG.info("Created database key directory"); + // If only the backup file exists, rename it so we don't overwrite it + if (dbKeyBackupFile.exists() && !dbKeyFile.exists()) { + if (dbKeyBackupFile.renameTo(dbKeyFile)) + LOG.info("Renamed old backup"); + else LOG.warning("Failed to rename old backup"); + } + try { + // Write to the backup file + writeDbKeyToFile(hex, dbKeyBackupFile); + LOG.info("Stored database key in backup file"); + // Delete the old primary file, if it exists + if (dbKeyFile.exists()) { + if (dbKeyFile.delete()) LOG.info("Deleted primary file"); + else LOG.warning("Failed to delete primary file"); + } + // The backup file becomes the new primary + if (dbKeyBackupFile.renameTo(dbKeyFile)) { + LOG.info("Renamed backup file to primary"); + } else { + LOG.warning("Failed to rename backup file to primary"); + return false; // Don't overwrite our only copy + } + // Write a second copy to the backup file + writeDbKeyToFile(hex, dbKeyBackupFile); + LOG.info("Stored second copy of database key in backup file"); + return true; + } catch (IOException e) { + logException(LOG, WARNING, e); + return false; + } + } + + private void writeDbKeyToFile(String key, File f) throws IOException { + FileOutputStream out = new FileOutputStream(f); + out.write(key.getBytes("UTF-8")); + out.flush(); + out.close(); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java index 66e5cfcf6..796e4bbe4 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.db; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DataTooNewException; import org.briarproject.bramble.api.db.DataTooOldException; import org.briarproject.bramble.api.db.DbException; @@ -48,7 +49,8 @@ interface Database { * @throws DataTooOldException if the data uses an older schema than the * current code and cannot be migrated */ - boolean open(@Nullable MigrationListener listener) throws DbException; + boolean open(SecretKey key, @Nullable MigrationListener listener) + throws DbException; /** * Prevents new transactions from starting, waits for all current @@ -641,7 +643,7 @@ interface Database { * Marks the given transport keys as usable for outgoing streams. */ void setTransportKeysActive(T txn, TransportId t, KeySetId k) - throws DbException; + throws DbException; /** * Updates the transmission count and expiry time of the given message diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java index f2e4de1c6..2913c783f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java @@ -6,6 +6,7 @@ import org.briarproject.bramble.api.contact.event.ContactAddedEvent; import org.briarproject.bramble.api.contact.event.ContactRemovedEvent; import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent; import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent; +import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.ContactExistsException; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DbException; @@ -103,9 +104,9 @@ class DatabaseComponentImpl implements DatabaseComponent { } @Override - public boolean open(@Nullable MigrationListener listener) + public boolean open(SecretKey key, @Nullable MigrationListener listener) throws DbException { - boolean reopened = db.open(listener); + boolean reopened = db.open(key, listener); shutdown.addShutdownHook(() -> { try { close(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/H2Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/H2Database.java index 1c1983e67..fd5be6905 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/H2Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/H2Database.java @@ -32,6 +32,9 @@ class H2Database extends JdbcDatabase { private final DatabaseConfig config; private final String url; + @Nullable + private volatile SecretKey key = null; + @Inject H2Database(DatabaseConfig config, Clock clock) { super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE, @@ -44,11 +47,12 @@ class H2Database extends JdbcDatabase { } @Override - public boolean open(@Nullable MigrationListener listener) + public boolean open(SecretKey key, @Nullable MigrationListener listener) throws DbException { + this.key = key; boolean reopen = config.databaseExists(); if (!reopen) config.getDatabaseDirectory().mkdirs(); - super.open("org.h2.Driver", reopen, listener); + super.open("org.h2.Driver", reopen, key, listener); return reopen; } @@ -63,7 +67,7 @@ class H2Database extends JdbcDatabase { } @Override - public long getFreeSpace() throws DbException { + public long getFreeSpace() { File dir = config.getDatabaseDirectory(); long maxSize = config.getMaxSize(); long free = dir.getFreeSpace(); @@ -88,7 +92,7 @@ class H2Database extends JdbcDatabase { @Override protected Connection createConnection() throws SQLException { - SecretKey key = config.getEncryptionKey(); + SecretKey key = this.key; if (key == null) throw new IllegalStateException(); Properties props = new Properties(); props.setProperty("user", "user"); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/HyperSqlDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/HyperSqlDatabase.java index 6a87ededa..0bfb66ea6 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/HyperSqlDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/HyperSqlDatabase.java @@ -33,6 +33,9 @@ class HyperSqlDatabase extends JdbcDatabase { private final DatabaseConfig config; private final String url; + @Nullable + private volatile SecretKey key = null; + @Inject HyperSqlDatabase(DatabaseConfig config, Clock clock) { super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE, @@ -46,10 +49,12 @@ class HyperSqlDatabase extends JdbcDatabase { } @Override - public boolean open(@Nullable MigrationListener listener) throws DbException { + public boolean open(SecretKey key, @Nullable MigrationListener listener) + throws DbException { + this.key = key; boolean reopen = config.databaseExists(); if (!reopen) config.getDatabaseDirectory().mkdirs(); - super.open("org.hsqldb.jdbc.JDBCDriver", reopen, listener); + super.open("org.hsqldb.jdbc.JDBCDriver", reopen, key, listener); return reopen; } @@ -93,7 +98,7 @@ class HyperSqlDatabase extends JdbcDatabase { @Override protected Connection createConnection() throws SQLException { - SecretKey key = config.getEncryptionKey(); + SecretKey key = this.key; if (key == null) throw new IllegalStateException(); String hex = StringUtils.toHexString(key.getBytes()); return DriverManager.getConnection(url + ";crypt_key=" + hex); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index baa67a29a..fd248f811 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -328,7 +328,7 @@ abstract class JdbcDatabase implements Database { this.clock = clock; } - protected void open(String driverClass, boolean reopen, + protected void open(String driverClass, boolean reopen, SecretKey key, @Nullable MigrationListener listener) throws DbException { // Load the JDBC driver try { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java index b99ab31e1..a2c4d7e3f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java @@ -1,5 +1,7 @@ package org.briarproject.bramble.lifecycle; +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DataTooNewException; import org.briarproject.bramble.api.db.DataTooOldException; import org.briarproject.bramble.api.db.DatabaseComponent; @@ -55,6 +57,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener { private final List services; private final List clients; private final List executors; + private final AccountManager accountManager; private final IdentityManager identityManager; private final Semaphore startStopSemaphore = new Semaphore(1); private final CountDownLatch dbLatch = new CountDownLatch(1); @@ -65,9 +68,10 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener { @Inject LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus, - IdentityManager identityManager) { + AccountManager accountManager, IdentityManager identityManager) { this.db = db; this.eventBus = eventBus; + this.accountManager = accountManager; this.identityManager = identityManager; services = new CopyOnWriteArrayList<>(); clients = new CopyOnWriteArrayList<>(); @@ -104,7 +108,9 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener { LOG.info("Starting services"); long start = now(); - boolean reopened = db.open(this); + SecretKey key = accountManager.getDatabaseKey(); + if (key == null) throw new IllegalStateException(); + boolean reopened = db.open(key, this); if (reopened) logDuration(LOG, "Reopening database", start); else logDuration(LOG, "Creating database", start); identityManager.storeLocalAuthor(); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java new file mode 100644 index 000000000..7e1f6124d --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java @@ -0,0 +1,158 @@ +package org.briarproject.bramble.account; + +import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.test.BrambleMockTestCase; +import org.jmock.Expectations; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; + +import javax.annotation.Nullable; + +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.getRandomBytes; +import static org.briarproject.bramble.test.TestUtils.getTestDirectory; +import static org.briarproject.bramble.util.StringUtils.toHexString; +import static org.junit.Assert.assertEquals; + +public class AccountManagerImplTest extends BrambleMockTestCase { + + private final DatabaseConfig databaseConfig = + context.mock(DatabaseConfig.class); + + private final byte[] encryptedKey = getRandomBytes(123); + private final String encryptedKeyHex = toHexString(encryptedKey); + private final String oldEncryptedKeyHex = toHexString(getRandomBytes(123)); + private final File testDir = getTestDirectory(); + private final File keyDir = new File(testDir, "key"); + private final File keyFile = new File(keyDir, "db.key"); + private final File keyBackupFile = new File(keyDir, "db.key.bak"); + + private AccountManagerImpl accountManager; + + @Before + public void setUp() { + context.checking(new Expectations() {{ + allowing(databaseConfig).getDatabaseKeyDirectory(); + will(returnValue(keyDir)); + }}); + accountManager = new AccountManagerImpl(databaseConfig); + } + + @Test + public void testDbKeyIsLoadedFromPrimaryFile() throws Exception { + assertFalse(keyFile.exists()); + assertFalse(keyBackupFile.exists()); + + storeDatabaseKey(keyFile, encryptedKeyHex); + + assertTrue(keyFile.exists()); + assertFalse(keyBackupFile.exists()); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + + assertEquals(encryptedKeyHex, accountManager.getEncryptedDatabaseKey()); + + assertTrue(keyFile.exists()); + assertFalse(keyBackupFile.exists()); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + } + + @Test + public void testDbKeyIsLoadedFromBackupFile() throws Exception { + assertFalse(keyFile.exists()); + assertFalse(keyBackupFile.exists()); + + storeDatabaseKey(keyBackupFile, encryptedKeyHex); + + assertFalse(keyFile.exists()); + assertTrue(keyBackupFile.exists()); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); + + assertEquals(encryptedKeyHex, accountManager.getEncryptedDatabaseKey()); + + assertFalse(keyFile.exists()); + assertTrue(keyBackupFile.exists()); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); + } + + @Test + public void testDbKeyIsNullIfNotFound() { + assertFalse(keyFile.exists()); + assertFalse(keyBackupFile.exists()); + + assertNull(accountManager.getEncryptedDatabaseKey()); + + assertFalse(keyFile.exists()); + assertFalse(keyBackupFile.exists()); + } + + @Test + public void testStoringDbKeyOverwritesPrimary() throws Exception { + assertFalse(keyFile.exists()); + assertFalse(keyBackupFile.exists()); + + storeDatabaseKey(keyFile, oldEncryptedKeyHex); + + assertTrue(keyFile.exists()); + assertFalse(keyBackupFile.exists()); + assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyFile)); + + assertTrue(accountManager.storeEncryptedDatabaseKey(encryptedKeyHex)); + + assertTrue(keyFile.exists()); + assertTrue(keyBackupFile.exists()); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); + } + + @Test + public void testStoringDbKeyOverwritesBackup() throws Exception { + assertFalse(keyFile.exists()); + assertFalse(keyBackupFile.exists()); + + storeDatabaseKey(keyBackupFile, oldEncryptedKeyHex); + + assertFalse(keyFile.exists()); + assertTrue(keyBackupFile.exists()); + assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyBackupFile)); + + assertTrue(accountManager.storeEncryptedDatabaseKey(encryptedKeyHex)); + + assertTrue(keyFile.exists()); + assertTrue(keyBackupFile.exists()); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); + } + + @After + public void tearDown() { + deleteTestDirectory(testDir); + } + + private void storeDatabaseKey(File f, String hex) throws IOException { + f.getParentFile().mkdirs(); + FileOutputStream out = new FileOutputStream(f); + out.write(hex.getBytes("UTF-8")); + out.flush(); + out.close(); + } + + @Nullable + private String loadDatabaseKey(File f) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader( + new FileInputStream(f), "UTF-8")); + String hex = reader.readLine(); + reader.close(); + return hex; + } +} diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java index e16e03da0..676cac2e3 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java @@ -89,6 +89,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { context.mock(ShutdownManager.class); private final EventBus eventBus = context.mock(EventBus.class); + private final SecretKey key = getSecretKey(); private final Object txn = new Object(); private final ClientId clientId; private final int majorVersion; @@ -141,7 +142,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { int shutdownHandle = 12345; context.checking(new Expectations() {{ // open() - oneOf(database).open(null); + oneOf(database).open(key, null); will(returnValue(false)); oneOf(shutdown).addShutdownHook(with(any(Runnable.class))); will(returnValue(shutdownHandle)); @@ -208,7 +209,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - assertFalse(db.open(null)); + assertFalse(db.open(key, null)); Transaction transaction = db.startTransaction(false); try { db.addLocalAuthor(transaction, localAuthor); @@ -1602,7 +1603,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { MessageId messageId2 = new MessageId(getRandomId()); context.checking(new Expectations() {{ // open() - oneOf(database).open(null); + oneOf(database).open(key, null); will(returnValue(false)); oneOf(shutdown).addShutdownHook(with(any(Runnable.class))); will(returnValue(shutdownHandle)); @@ -1646,7 +1647,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - assertFalse(db.open(null)); + assertFalse(db.open(key, null)); Transaction transaction = db.startTransaction(false); try { db.addLocalMessage(transaction, message, metadata, true); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseMigrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseMigrationTest.java index 89bdf8a4c..0740bdfc2 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseMigrationTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseMigrationTest.java @@ -1,5 +1,6 @@ package org.briarproject.bramble.db; +import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DataTooNewException; import org.briarproject.bramble.api.db.DataTooOldException; import org.briarproject.bramble.api.db.DatabaseConfig; @@ -26,6 +27,7 @@ import static java.util.Collections.singletonList; import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE; import static org.briarproject.bramble.db.DatabaseConstants.SCHEMA_VERSION_KEY; import static org.briarproject.bramble.db.JdbcDatabase.CODE_SCHEMA_VERSION; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -43,6 +45,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase { protected final DatabaseConfig config = new TestDatabaseConfig(testDir, 1024 * 1024); + protected final SecretKey key = getSecretKey(); protected final Clock clock = new SystemClock(); abstract Database createDatabase( @@ -62,7 +65,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase { public void testDoesNotRunMigrationsWhenCreatingDatabase() throws Exception { Database db = createDatabase(singletonList(migration)); - assertFalse(db.open(null)); + assertFalse(db.open(key, null)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); db.close(); } @@ -72,14 +75,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase { throws Exception { // Open the DB for the first time Database db = createDatabase(asList(migration, migration1)); - assertFalse(db.open(null)); + assertFalse(db.open(key, null)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); // Override the data schema version setDataSchemaVersion(db, -1); db.close(); // Reopen the DB - an exception should be thrown db = createDatabase(asList(migration, migration1)); - db.open(null); + db.open(key, null); } @Test @@ -87,12 +90,12 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase { throws Exception { // Open the DB for the first time Database db = createDatabase(asList(migration, migration1)); - assertFalse(db.open(null)); + assertFalse(db.open(key, null)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); db.close(); // Reopen the DB - migrations should not be run db = createDatabase(asList(migration, migration1)); - assertTrue(db.open(null)); + assertTrue(db.open(key, null)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); db.close(); } @@ -101,14 +104,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase { public void testThrowsExceptionIfDataIsNewerThanCode() throws Exception { // Open the DB for the first time Database db = createDatabase(asList(migration, migration1)); - assertFalse(db.open(null)); + assertFalse(db.open(key, null)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); // Override the data schema version setDataSchemaVersion(db, CODE_SCHEMA_VERSION + 1); db.close(); // Reopen the DB - an exception should be thrown db = createDatabase(asList(migration, migration1)); - db.open(null); + db.open(key, null); } @Test(expected = DataTooOldException.class) @@ -116,13 +119,13 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase { throws Exception { // Open the DB for the first time Database db = createDatabase(emptyList()); - assertFalse(db.open(null)); + assertFalse(db.open(key, null)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 1); db.close(); // Reopen the DB - an exception should be thrown db = createDatabase(emptyList()); - db.open(null); + db.open(key, null); } @Test(expected = DataTooOldException.class) @@ -141,14 +144,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase { // Open the DB for the first time Database db = createDatabase(asList(migration, migration1)); - assertFalse(db.open(null)); + assertFalse(db.open(key, null)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); // Override the data schema version setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 3); db.close(); // Reopen the DB - an exception should be thrown db = createDatabase(asList(migration, migration1)); - db.open(null); + db.open(key, null); } @Test @@ -170,14 +173,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase { // Open the DB for the first time Database db = createDatabase(asList(migration, migration1)); - assertFalse(db.open(null)); + assertFalse(db.open(key, null)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); // Override the data schema version setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2); db.close(); // Reopen the DB - the first migration should be run db = createDatabase(asList(migration, migration1)); - assertTrue(db.open(null)); + assertTrue(db.open(key, null)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); db.close(); } @@ -202,14 +205,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase { // Open the DB for the first time Database db = createDatabase(asList(migration, migration1)); - assertFalse(db.open(null)); + assertFalse(db.open(key, null)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); // Override the data schema version setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2); db.close(); // Reopen the DB - both migrations should be run db = createDatabase(asList(migration, migration1)); - assertTrue(db.open(null)); + assertTrue(db.open(key, null)); assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db)); db.close(); } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabasePerformanceComparisonTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabasePerformanceComparisonTest.java index 1807d30dc..279d1b56e 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabasePerformanceComparisonTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabasePerformanceComparisonTest.java @@ -15,6 +15,7 @@ import java.util.List; import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; import static org.briarproject.bramble.test.TestUtils.getMean; import static org.briarproject.bramble.test.TestUtils.getMedian; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getStandardDeviation; import static org.briarproject.bramble.test.UTest.Z_CRITICAL_0_01; @@ -71,7 +72,7 @@ public abstract class DatabasePerformanceComparisonTest throws DbException { Database db = createDatabase(conditionA, new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock()); - db.open(null); + db.open(getSecretKey(), null); return db; } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseTraceTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseTraceTest.java index f4e0daa19..2060ca71e 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseTraceTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseTraceTest.java @@ -16,6 +16,7 @@ import java.sql.Connection; import javax.annotation.Nullable; import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; public abstract class DatabaseTraceTest extends DatabasePerformanceTest { @@ -43,7 +44,7 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest { private Database openDatabase() throws DbException { Database db = createDatabase( new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock()); - db.open(null); + db.open(getSecretKey(), null); return db; } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/H2MigrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/H2MigrationTest.java index 6a868fd42..29bdbfa5f 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/H2MigrationTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/H2MigrationTest.java @@ -9,8 +9,8 @@ import java.util.List; public class H2MigrationTest extends DatabaseMigrationTest { @Override - Database createDatabase(List> migrations) - throws Exception { + Database createDatabase( + List> migrations) { return new H2Database(config, clock) { @Override List> getMigrations() { diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java index 2655e9ef7..e88038258 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java @@ -64,6 +64,7 @@ import static org.briarproject.bramble.test.TestUtils.getLocalAuthor; 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; import static org.briarproject.bramble.test.TestUtils.getTransportId; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -79,7 +80,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { private static final int ONE_MEGABYTE = 1024 * 1024; private static final int MAX_SIZE = 5 * ONE_MEGABYTE; - private final File testDir = TestUtils.getTestDirectory(); + private final SecretKey key = getSecretKey(); + private final File testDir = getTestDirectory(); private final GroupId groupId; private final ClientId clientId; private final int majorVersion; @@ -96,7 +98,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { private final KeySetId keySetId, keySetId1; private final Random random = new Random(); - JdbcDatabaseTest() throws Exception { + JdbcDatabaseTest() { clientId = getClientId(); majorVersion = 123; group = getGroup(clientId, majorVersion); @@ -1819,7 +1821,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { Database db = createDatabase( new TestDatabaseConfig(testDir, MAX_SIZE), clock); if (!resume) TestUtils.deleteTestDirectory(testDir); - db.open(null); + db.open(key, null); return db; } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/SingleDatabasePerformanceTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/SingleDatabasePerformanceTest.java index 670c7cddb..6256d39cd 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/SingleDatabasePerformanceTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/SingleDatabasePerformanceTest.java @@ -13,6 +13,7 @@ import java.util.List; import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; import static org.briarproject.bramble.test.TestUtils.getMean; import static org.briarproject.bramble.test.TestUtils.getMedian; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getStandardDeviation; public abstract class SingleDatabasePerformanceTest @@ -40,7 +41,7 @@ public abstract class SingleDatabasePerformanceTest private Database openDatabase() throws DbException { Database db = createDatabase( new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock()); - db.open(null); + db.open(getSecretKey(), null); return db; } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/test/TestDatabaseConfig.java b/bramble-core/src/test/java/org/briarproject/bramble/test/TestDatabaseConfig.java index 7e5ad34e7..89f68a30e 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/test/TestDatabaseConfig.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/test/TestDatabaseConfig.java @@ -1,6 +1,5 @@ package org.briarproject.bramble.test; -import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; @@ -11,7 +10,6 @@ public class TestDatabaseConfig implements DatabaseConfig { private final File dbDir, keyDir; private final long maxSize; - private volatile SecretKey key = new SecretKey(new byte[SecretKey.LENGTH]); public TestDatabaseConfig(File testDir, long maxSize) { dbDir = new File(testDir, "db"); @@ -36,16 +34,6 @@ public class TestDatabaseConfig implements DatabaseConfig { return keyDir; } - @Override - public void setEncryptionKey(SecretKey key) { - this.key = key; - } - - @Override - public SecretKey getEncryptionKey() { - return key; - } - @Override public long getMaxSize() { return maxSize; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidDatabaseConfig.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidDatabaseConfig.java index 1f21acdb0..9aa2ac6ae 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidDatabaseConfig.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidDatabaseConfig.java @@ -1,14 +1,11 @@ package org.briarproject.briar.android; -import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import java.io.File; import java.util.logging.Logger; -import javax.annotation.Nullable; - import static java.util.logging.Level.INFO; @NotNullByDefault @@ -19,9 +16,6 @@ class AndroidDatabaseConfig implements DatabaseConfig { private final File dbDir, keyDir; - @Nullable - private volatile SecretKey key = null; - AndroidDatabaseConfig(File dbDir, File keyDir) { this.dbDir = dbDir; this.keyDir = keyDir; @@ -62,21 +56,6 @@ class AndroidDatabaseConfig implements DatabaseConfig { return keyDir; } - @Override - public void setEncryptionKey(SecretKey key) { - LOG.info("Setting database key"); - this.key = key; - } - - @Override - @Nullable - public SecretKey getEncryptionKey() { - SecretKey key = this.key; - if (LOG.isLoggable(INFO)) - LOG.info("Database key has been set: " + (key != null)); - return key; - } - @Override public long getMaxSize() { return Long.MAX_VALUE; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java index cb0d2c3c3..1f7305371 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java @@ -9,20 +9,11 @@ import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.util.AndroidUtils; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; import java.util.logging.Logger; import javax.annotation.Nullable; import javax.inject.Inject; -import static java.util.logging.Level.WARNING; -import static org.briarproject.bramble.util.LogUtils.logException; - @NotNullByDefault public class ConfigControllerImpl implements ConfigController { @@ -30,12 +21,9 @@ public class ConfigControllerImpl implements ConfigController { Logger.getLogger(ConfigControllerImpl.class.getName()); private static final String PREF_DB_KEY = "key"; - private static final String DB_KEY_FILENAME = "db.key"; - private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak"; private final SharedPreferences briarPrefs; - private final File dbKeyFile, dbKeyBackupFile; - private final AccountManager accountManager; + protected final AccountManager accountManager; protected final DatabaseConfig databaseConfig; @Inject @@ -44,16 +32,13 @@ public class ConfigControllerImpl implements ConfigController { this.briarPrefs = briarPrefs; this.accountManager = accountManager; this.databaseConfig = databaseConfig; - File keyDir = databaseConfig.getDatabaseKeyDirectory(); - dbKeyFile = new File(keyDir, DB_KEY_FILENAME); - dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME); } @Override @Nullable public String getEncryptedDatabaseKey() { String key = getDatabaseKeyFromPreferences(); - if (key == null) key = getDatabaseKeyFromFile(); + if (key == null) key = accountManager.getEncryptedDatabaseKey(); else migrateDatabaseKeyToFile(key); return key; } @@ -66,40 +51,8 @@ public class ConfigControllerImpl implements ConfigController { return key; } - @Nullable - private String getDatabaseKeyFromFile() { - String key = readDbKeyFromFile(dbKeyFile); - if (key == null) { - LOG.info("No database key in primary file"); - key = readDbKeyFromFile(dbKeyBackupFile); - if (key == null) LOG.info("No database key in backup file"); - else LOG.warning("Found database key in backup file"); - } else { - LOG.info("Found database key in primary file"); - } - return key; - } - - @Nullable - private String readDbKeyFromFile(File f) { - if (!f.exists()) { - LOG.info("Key file does not exist"); - return null; - } - try { - BufferedReader reader = new BufferedReader(new InputStreamReader( - new FileInputStream(f), "UTF-8")); - String key = reader.readLine(); - reader.close(); - return key; - } catch (IOException e) { - logException(LOG, WARNING, e); - return null; - } - } - private void migrateDatabaseKeyToFile(String key) { - if (storeEncryptedDatabaseKey(key)) { + if (accountManager.storeEncryptedDatabaseKey(key)) { if (briarPrefs.edit().remove(PREF_DB_KEY).commit()) LOG.info("Database key migrated to file"); else LOG.warning("Database key not removed from preferences"); @@ -110,47 +63,7 @@ public class ConfigControllerImpl implements ConfigController { @Override public boolean storeEncryptedDatabaseKey(String hex) { - LOG.info("Storing database key in file"); - // Create the directory if necessary - if (databaseConfig.getDatabaseKeyDirectory().mkdirs()) - LOG.info("Created database key directory"); - // If only the backup file exists, rename it so we don't overwrite it - if (dbKeyBackupFile.exists() && !dbKeyFile.exists()) { - if (dbKeyBackupFile.renameTo(dbKeyFile)) - LOG.info("Renamed old backup"); - else LOG.warning("Failed to rename old backup"); - } - try { - // Write to the backup file - writeDbKeyToFile(hex, dbKeyBackupFile); - LOG.info("Stored database key in backup file"); - // Delete the old primary file, if it exists - if (dbKeyFile.exists()) { - if (dbKeyFile.delete()) LOG.info("Deleted primary file"); - else LOG.warning("Failed to delete primary file"); - } - // The backup file becomes the new primary - if (dbKeyBackupFile.renameTo(dbKeyFile)) { - LOG.info("Renamed backup file to primary"); - } else { - LOG.warning("Failed to rename backup file to primary"); - return false; // Don't overwrite our only copy - } - // Write a second copy to the backup file - writeDbKeyToFile(hex, dbKeyBackupFile); - LOG.info("Stored second copy of database key in backup file"); - return true; - } catch (IOException e) { - logException(LOG, WARNING, e); - return false; - } - } - - private void writeDbKeyToFile(String key, File f) throws IOException { - FileOutputStream out = new FileOutputStream(f); - out.write(key.getBytes("UTF-8")); - out.flush(); - out.close(); + return accountManager.storeEncryptedDatabaseKey(hex); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java index ca9634502..5a3cd5b8d 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java @@ -57,7 +57,7 @@ public class PasswordControllerImpl extends ConfigControllerImpl if (key == null) { resultHandler.onResult(false); } else { - databaseConfig.setEncryptionKey(new SecretKey(key)); + accountManager.setDatabaseKey(new SecretKey(key)); resultHandler.onResult(true); } }); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java index 30d039849..a2395d894 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java @@ -115,7 +115,7 @@ public class SetupControllerImpl extends PasswordControllerImpl SecretKey key = crypto.generateSecretKey(); String hex = encryptDatabaseKey(key, password); storeEncryptedDatabaseKey(hex); - databaseConfig.setEncryptionKey(key); + accountManager.setDatabaseKey(key); resultHandler.onResult(null); }); } diff --git a/briar-android/src/test/java/org/briarproject/briar/android/TestDatabaseKeyUtils.java b/briar-android/src/test/java/org/briarproject/briar/android/TestDatabaseKeyUtils.java deleted file mode 100644 index 0e9173105..000000000 --- a/briar-android/src/test/java/org/briarproject/briar/android/TestDatabaseKeyUtils.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.briarproject.briar.android; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; - -import javax.annotation.Nullable; - -import static junit.framework.Assert.assertTrue; - -@NotNullByDefault -public class TestDatabaseKeyUtils { - - public static void storeDatabaseKey(File f, String hex) throws IOException { - f.getParentFile().mkdirs(); - FileOutputStream out = new FileOutputStream(f); - out.write(hex.getBytes("UTF-8")); - out.flush(); - out.close(); - } - - @Nullable - public static String loadDatabaseKey(File f) throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader( - new FileInputStream(f), "UTF-8")); - String hex = reader.readLine(); - reader.close(); - return hex; - } -} diff --git a/briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java index d8e4445c2..06f1165ab 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java @@ -7,21 +7,11 @@ import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.test.BrambleMockTestCase; import org.jmock.Expectations; -import org.junit.After; import org.junit.Test; -import java.io.File; - import static junit.framework.Assert.assertEquals; -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.getRandomBytes; -import static org.briarproject.bramble.test.TestUtils.getTestDirectory; import static org.briarproject.bramble.util.StringUtils.toHexString; -import static org.briarproject.briar.android.TestDatabaseKeyUtils.loadDatabaseKey; -import static org.briarproject.briar.android.TestDatabaseKeyUtils.storeDatabaseKey; public class ConfigControllerImplTest extends BrambleMockTestCase { @@ -33,21 +23,15 @@ public class ConfigControllerImplTest extends BrambleMockTestCase { context.mock(DatabaseConfig.class); private final Editor editor = context.mock(Editor.class); - private final byte[] encryptedKey = getRandomBytes(123); - private final String encryptedKeyHex = toHexString(encryptedKey); - private final String oldEncryptedKeyHex = toHexString(getRandomBytes(123)); - private final File testDir = getTestDirectory(); - private final File keyDir = new File(testDir, "key"); - private final File keyFile = new File(keyDir, "db.key"); - private final File keyBackupFile = new File(keyDir, "db.key.bak"); + private final String encryptedKeyHex = toHexString(getRandomBytes(123)); @Test - public void testDbKeyIsMigratedFromPreferencesToFile() throws Exception { + public void testDbKeyIsMigratedFromPreferencesToFile() { context.checking(new Expectations() {{ oneOf(prefs).getString("key", null); will(returnValue(encryptedKeyHex)); - allowing(databaseConfig).getDatabaseKeyDirectory(); - will(returnValue(keyDir)); + oneOf(accountManager).storeEncryptedDatabaseKey(encryptedKeyHex); + will(returnValue(true)); oneOf(prefs).edit(); will(returnValue(editor)); oneOf(editor).remove("key"); @@ -56,153 +40,10 @@ public class ConfigControllerImplTest extends BrambleMockTestCase { will(returnValue(true)); }}); - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager, databaseConfig); assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey()); - - assertTrue(keyFile.exists()); - assertTrue(keyBackupFile.exists()); - assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); - assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); } - @Test - public void testDbKeyIsLoadedFromPrimaryFile() throws Exception { - context.checking(new Expectations() {{ - oneOf(prefs).getString("key", null); - will(returnValue(null)); - allowing(databaseConfig).getDatabaseKeyDirectory(); - will(returnValue(keyDir)); - }}); - - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - - storeDatabaseKey(keyFile, encryptedKeyHex); - - assertTrue(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); - - ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager, - databaseConfig); - - assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey()); - - assertTrue(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); - } - - @Test - public void testDbKeyIsLoadedFromBackupFile() throws Exception { - context.checking(new Expectations() {{ - oneOf(prefs).getString("key", null); - will(returnValue(null)); - allowing(databaseConfig).getDatabaseKeyDirectory(); - will(returnValue(keyDir)); - }}); - - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - - storeDatabaseKey(keyBackupFile, encryptedKeyHex); - - assertFalse(keyFile.exists()); - assertTrue(keyBackupFile.exists()); - assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); - - ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager, - databaseConfig); - - assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey()); - - assertFalse(keyFile.exists()); - assertTrue(keyBackupFile.exists()); - assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); - } - - @Test - public void testDbKeyIsNullIfNotFound() { - context.checking(new Expectations() {{ - oneOf(prefs).getString("key", null); - will(returnValue(null)); - allowing(databaseConfig).getDatabaseKeyDirectory(); - will(returnValue(keyDir)); - }}); - - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - - ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager, - databaseConfig); - - assertNull(c.getEncryptedDatabaseKey()); - - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - } - - @Test - public void testStoringDbKeyOverwritesPrimary() throws Exception { - context.checking(new Expectations() {{ - allowing(databaseConfig).getDatabaseKeyDirectory(); - will(returnValue(keyDir)); - }}); - - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - - storeDatabaseKey(keyFile, oldEncryptedKeyHex); - - assertTrue(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyFile)); - - ConfigController c = new ConfigControllerImpl(prefs, accountManager, - databaseConfig); - - assertTrue(c.storeEncryptedDatabaseKey(encryptedKeyHex)); - - assertTrue(keyFile.exists()); - assertTrue(keyBackupFile.exists()); - assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); - assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); - } - - @Test - public void testStoringDbKeyOverwritesBackup() throws Exception { - context.checking(new Expectations() {{ - allowing(databaseConfig).getDatabaseKeyDirectory(); - will(returnValue(keyDir)); - }}); - - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - - storeDatabaseKey(keyBackupFile, oldEncryptedKeyHex); - - assertFalse(keyFile.exists()); - assertTrue(keyBackupFile.exists()); - assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyBackupFile)); - - ConfigController c = new ConfigControllerImpl(prefs, accountManager, - databaseConfig); - - assertTrue(c.storeEncryptedDatabaseKey(encryptedKeyHex)); - - assertTrue(keyFile.exists()); - assertTrue(keyBackupFile.exists()); - assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); - assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); - } - - @After - public void tearDown() { - deleteTestDirectory(testDir); - } } diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java index dcc2685b6..9c64083cd 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java @@ -9,23 +9,16 @@ import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.ImmediateExecutor; import org.jmock.Expectations; -import org.junit.After; import org.junit.Test; -import java.io.File; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; -import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; -import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getSecretKey; -import static org.briarproject.bramble.test.TestUtils.getTestDirectory; import static org.briarproject.bramble.util.StringUtils.toHexString; -import static org.briarproject.briar.android.TestDatabaseKeyUtils.loadDatabaseKey; -import static org.briarproject.briar.android.TestDatabaseKeyUtils.storeDatabaseKey; public class PasswordControllerImplTest extends BrambleMockTestCase { @@ -46,32 +39,27 @@ public class PasswordControllerImplTest extends BrambleMockTestCase { private final byte[] oldEncryptedKey = getRandomBytes(123); private final byte[] newEncryptedKey = getRandomBytes(123); private final byte[] key = getSecretKey().getBytes(); - private final File testDir = getTestDirectory(); - private final File keyDir = new File(testDir, "key"); - private final File keyFile = new File(keyDir, "db.key"); - private final File keyBackupFile = new File(keyDir, "db.key.bak"); + private final String oldEncryptedKeyHex = toHexString(oldEncryptedKey); + private final String newEncryptedKeyHex = toHexString(newEncryptedKey); @Test - public void testChangePasswordReturnsTrue() throws Exception { + public void testChangePasswordReturnsTrue() { context.checking(new Expectations() {{ // Look up the encrypted DB key oneOf(briarPrefs).getString("key", null); will(returnValue(null)); - allowing(databaseConfig).getDatabaseKeyDirectory(); - will(returnValue(keyDir)); + oneOf(accountManager).getEncryptedDatabaseKey(); + will(returnValue(oldEncryptedKeyHex)); // Decrypt and re-encrypt the key oneOf(crypto).decryptWithPassword(oldEncryptedKey, oldPassword); will(returnValue(key)); oneOf(crypto).encryptWithPassword(key, newPassword); will(returnValue(newEncryptedKey)); + // Store the new key + oneOf(accountManager).storeEncryptedDatabaseKey(newEncryptedKeyHex); + will(returnValue(true)); }}); - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - - storeDatabaseKey(keyFile, toHexString(oldEncryptedKey)); - storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey)); - PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs, accountManager, databaseConfig, cryptoExecutor, crypto, estimator); @@ -79,34 +67,21 @@ public class PasswordControllerImplTest extends BrambleMockTestCase { AtomicBoolean capturedResult = new AtomicBoolean(false); p.changePassword(oldPassword, newPassword, capturedResult::set); assertTrue(capturedResult.get()); - - assertTrue(keyFile.exists()); - assertTrue(keyBackupFile.exists()); - assertEquals(toHexString(newEncryptedKey), loadDatabaseKey(keyFile)); - assertEquals(toHexString(newEncryptedKey), - loadDatabaseKey(keyBackupFile)); } @Test - public void testChangePasswordReturnsFalseIfOldPasswordIsWrong() - throws Exception { + public void testChangePasswordReturnsFalseIfOldPasswordIsWrong() { context.checking(new Expectations() {{ // Look up the encrypted DB key oneOf(briarPrefs).getString("key", null); will(returnValue(null)); - allowing(databaseConfig).getDatabaseKeyDirectory(); - will(returnValue(keyDir)); + oneOf(accountManager).getEncryptedDatabaseKey(); + will(returnValue(oldEncryptedKeyHex)); // Try to decrypt the key - the password is wrong oneOf(crypto).decryptWithPassword(oldEncryptedKey, oldPassword); will(returnValue(null)); }}); - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - - storeDatabaseKey(keyFile, toHexString(oldEncryptedKey)); - storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey)); - PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs, accountManager, databaseConfig, cryptoExecutor, crypto, estimator); @@ -114,16 +89,5 @@ public class PasswordControllerImplTest extends BrambleMockTestCase { AtomicBoolean capturedResult = new AtomicBoolean(true); p.changePassword(oldPassword, newPassword, capturedResult::set); assertFalse(capturedResult.get()); - - assertTrue(keyFile.exists()); - assertTrue(keyBackupFile.exists()); - assertEquals(toHexString(oldEncryptedKey), loadDatabaseKey(keyFile)); - assertEquals(toHexString(oldEncryptedKey), - loadDatabaseKey(keyBackupFile)); - } - - @After - public void tearDown() { - deleteTestDirectory(testDir); } } diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java index dd8825147..4671bb1c4 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java @@ -1,7 +1,6 @@ package org.briarproject.briar.android.login; import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.CryptoComponent; @@ -14,25 +13,18 @@ import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.ImmediateExecutor; import org.jmock.Expectations; import org.jmock.lib.legacy.ClassImposteriser; -import org.junit.After; import org.junit.Test; -import java.io.File; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; -import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; import static org.briarproject.bramble.test.TestUtils.getLocalAuthor; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getSecretKey; -import static org.briarproject.bramble.test.TestUtils.getTestDirectory; import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.bramble.util.StringUtils.toHexString; -import static org.briarproject.briar.android.TestDatabaseKeyUtils.loadDatabaseKey; public class SetupControllerImplTest extends BrambleMockTestCase { @@ -55,11 +47,8 @@ public class SetupControllerImplTest extends BrambleMockTestCase { private final String password = "some.strong.pass"; private final LocalAuthor localAuthor = getLocalAuthor(); private final byte[] encryptedKey = getRandomBytes(123); + private final String encryptedKeyHex = toHexString(encryptedKey); private final SecretKey key = getSecretKey(); - private final File testDir = getTestDirectory(); - private final File keyDir = new File(testDir, "key"); - private final File keyFile = new File(keyDir, "db.key"); - private final File keyBackupFile = new File(keyDir, "db.key.bak"); public SetupControllerImplTest() { context.setImposteriser(ClassImposteriser.INSTANCE); @@ -68,13 +57,8 @@ public class SetupControllerImplTest extends BrambleMockTestCase { @Test @SuppressWarnings("ResultOfMethodCallIgnored") - public void testCreateAccount() throws Exception { + public void testCreateAccount() { context.checking(new Expectations() {{ - // Allow the contents of the data directory to be logged - allowing(setupActivity).getApplicationInfo(); - will(returnValue(new ApplicationInfo() {{ - dataDir = testDir.getAbsolutePath(); - }})); // Set the author name and password oneOf(setupActivity).setAuthorName(authorName); oneOf(setupActivity).setPassword(password); @@ -94,15 +78,12 @@ public class SetupControllerImplTest extends BrambleMockTestCase { oneOf(crypto).encryptWithPassword(key.getBytes(), password); will(returnValue(encryptedKey)); // Store the encrypted key - allowing(databaseConfig).getDatabaseKeyDirectory(); - will(returnValue(keyDir)); - // Attach the database key to the database config - oneOf(databaseConfig).setEncryptionKey(key); + oneOf(accountManager).storeEncryptedDatabaseKey(encryptedKeyHex); + will(returnValue(true)); + // Pass the database key to the account manager + oneOf(accountManager).setDatabaseKey(key); }}); - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - SetupControllerImpl s = new SetupControllerImpl(briarPrefs, accountManager, databaseConfig, cryptoExecutor, crypto, estimator, identityManager); @@ -113,17 +94,5 @@ public class SetupControllerImplTest extends BrambleMockTestCase { s.setPassword(password); s.createAccount(result -> called.set(true)); assertTrue(called.get()); - - assertTrue(keyFile.exists()); - assertTrue(keyBackupFile.exists()); - assertEquals(toHexString(encryptedKey), - loadDatabaseKey(keyFile)); - assertEquals(toHexString(encryptedKey), - loadDatabaseKey(keyBackupFile)); - } - - @After - public void tearDown() { - deleteTestDirectory(testDir); } } diff --git a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java index fec963b33..7aafa6ce4 100644 --- a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java @@ -27,6 +27,7 @@ import org.junit.Test; import java.io.File; import java.util.Collection; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -53,6 +54,8 @@ public class FeedManagerIntegrationTest extends BriarTestCase { LocalAuthor localAuthor = identityManager.createLocalAuthor("feedTest"); identityManager.registerLocalAuthor(localAuthor); + component.getAccountManager().setDatabaseKey(getSecretKey()); + lifecycleManager = component.getLifecycleManager(); lifecycleManager.startServices(); lifecycleManager.waitForStartup(); diff --git a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java index 685eedacb..3fc4a9ea6 100644 --- a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java @@ -1,5 +1,7 @@ package org.briarproject.briar.feed; +import org.briarproject.bramble.account.AccountModule; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.client.ClientModule; @@ -36,6 +38,7 @@ import dagger.Component; TestSecureRandomModule.class, TestSocksModule.class, TestDnsModule.class, + AccountModule.class, BriarClientModule.class, ClientModule.class, ContactModule.class, @@ -79,6 +82,8 @@ interface FeedManagerIntegrationTestComponent { IdentityManager getIdentityManager(); + AccountManager getAccountManager(); + LifecycleManager getLifecycleManager(); FeedManager getFeedManager(); diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java index 108f48849..2da286b05 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java @@ -1,5 +1,6 @@ package org.briarproject.briar.introduction; +import org.briarproject.bramble.account.AccountModule; import org.briarproject.bramble.client.ClientModule; import org.briarproject.bramble.contact.ContactModule; import org.briarproject.bramble.crypto.CryptoExecutorModule; @@ -36,6 +37,7 @@ import dagger.Component; TestDatabaseModule.class, TestPluginConfigModule.class, TestSecureRandomModule.class, + AccountModule.class, BlogModule.class, BriarClientModule.class, ClientModule.class, diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java index 5c8b0ca65..c846c1c73 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java @@ -100,6 +100,8 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { private ContactId setUp(SimplexMessagingIntegrationTestComponent device, LocalAuthor local, Author remote, boolean alice) throws Exception { + // Create a database key + device.getAccountManager().setDatabaseKey(getSecretKey()); // Add an identity for the user IdentityManager identityManager = device.getIdentityManager(); identityManager.registerLocalAuthor(local); diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java index 7dade1ed1..a5f9d9bc6 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java @@ -1,5 +1,7 @@ package org.briarproject.briar.messaging; +import org.briarproject.bramble.account.AccountModule; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.identity.IdentityManager; @@ -39,6 +41,7 @@ import dagger.Component; TestDatabaseModule.class, TestPluginConfigModule.class, TestSecureRandomModule.class, + AccountModule.class, BriarClientModule.class, ClientModule.class, ContactModule.class, @@ -77,6 +80,8 @@ interface SimplexMessagingIntegrationTestComponent { IdentityManager getIdentityManager(); + AccountManager getAccountManager(); + ContactManager getContactManager(); MessagingManager getMessagingManager(); diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java index 9f2ecec4a..0e30fa848 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java @@ -140,6 +140,9 @@ public abstract class BriarIntegrationTest Date: Thu, 26 Jul 2018 15:57:37 +0100 Subject: [PATCH 04/18] Remove logic from DatabaseConfig. --- .../bramble/api/db/DatabaseConfig.java | 2 -- .../briarproject/bramble/db/H2Database.java | 3 +- .../bramble/db/HyperSqlDatabase.java | 3 +- .../bramble/test/TestDatabaseConfig.java | 7 ----- .../briar/android/AndroidDatabaseConfig.java | 31 ------------------- .../briarproject/briar/android/AppModule.java | 8 +---- .../controller/ConfigControllerImpl.java | 4 +-- .../android/login/SignInReminderReceiver.java | 3 +- 8 files changed, 7 insertions(+), 54 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java index a9a95c47a..f096f1fec 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseConfig.java @@ -7,8 +7,6 @@ import java.io.File; @NotNullByDefault public interface DatabaseConfig { - boolean databaseExists(); - File getDatabaseDirectory(); File getDatabaseKeyDirectory(); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/H2Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/H2Database.java index fd5be6905..f400d1ce9 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/H2Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/H2Database.java @@ -50,8 +50,7 @@ class H2Database extends JdbcDatabase { public boolean open(SecretKey key, @Nullable MigrationListener listener) throws DbException { this.key = key; - boolean reopen = config.databaseExists(); - if (!reopen) config.getDatabaseDirectory().mkdirs(); + boolean reopen = !config.getDatabaseDirectory().mkdirs(); super.open("org.h2.Driver", reopen, key, listener); return reopen; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/HyperSqlDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/HyperSqlDatabase.java index 0bfb66ea6..447537d8c 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/HyperSqlDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/HyperSqlDatabase.java @@ -52,8 +52,7 @@ class HyperSqlDatabase extends JdbcDatabase { public boolean open(SecretKey key, @Nullable MigrationListener listener) throws DbException { this.key = key; - boolean reopen = config.databaseExists(); - if (!reopen) config.getDatabaseDirectory().mkdirs(); + boolean reopen = !config.getDatabaseDirectory().mkdirs(); super.open("org.hsqldb.jdbc.JDBCDriver", reopen, key, listener); return reopen; } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/test/TestDatabaseConfig.java b/bramble-core/src/test/java/org/briarproject/bramble/test/TestDatabaseConfig.java index 89f68a30e..1c626b483 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/test/TestDatabaseConfig.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/test/TestDatabaseConfig.java @@ -17,13 +17,6 @@ public class TestDatabaseConfig implements DatabaseConfig { this.maxSize = maxSize; } - @Override - public boolean databaseExists() { - if (!dbDir.isDirectory()) return false; - File[] files = dbDir.listFiles(); - return files != null && files.length > 0; - } - @Override public File getDatabaseDirectory() { return dbDir; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidDatabaseConfig.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidDatabaseConfig.java index 9aa2ac6ae..797fb907c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidDatabaseConfig.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidDatabaseConfig.java @@ -4,16 +4,10 @@ import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import java.io.File; -import java.util.logging.Logger; - -import static java.util.logging.Level.INFO; @NotNullByDefault class AndroidDatabaseConfig implements DatabaseConfig { - private static final Logger LOG = - Logger.getLogger(AndroidDatabaseConfig.class.getName()); - private final File dbDir, keyDir; AndroidDatabaseConfig(File dbDir, File keyDir) { @@ -21,38 +15,13 @@ class AndroidDatabaseConfig implements DatabaseConfig { this.keyDir = keyDir; } - @Override - public boolean databaseExists() { - // FIXME should not run on UiThread #620 - if (!dbDir.isDirectory()) { - if (LOG.isLoggable(INFO)) - LOG.info(dbDir.getAbsolutePath() + " is not a directory"); - return false; - } - File[] files = dbDir.listFiles(); - if (LOG.isLoggable(INFO)) { - if (files == null) { - LOG.info("Could not list files in " + dbDir.getAbsolutePath()); - } else { - LOG.info("Files in " + dbDir.getAbsolutePath() + ":"); - for (File f : files) LOG.info(f.getName()); - } - LOG.info("Database exists: " + (files != null && files.length > 0)); - } - return files != null && files.length > 0; - } - @Override public File getDatabaseDirectory() { - if (LOG.isLoggable(INFO)) - LOG.info("Database directory: " + dbDir.getAbsolutePath()); return dbDir; } @Override public File getDatabaseKeyDirectory() { - if (LOG.isLoggable(INFO)) - LOG.info("Database key directory: " + keyDir.getAbsolutePath()); return keyDir; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java index 2296a8baf..3af716277 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java @@ -11,9 +11,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; -import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.plugin.BackoffFactory; import org.briarproject.bramble.api.plugin.PluginConfig; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; @@ -86,11 +84,7 @@ public class AppModule { File dbDir = app.getApplicationContext().getDir("db", MODE_PRIVATE); File keyDir = app.getApplicationContext().getDir("key", MODE_PRIVATE); StrictMode.setThreadPolicy(tp); - @MethodsNotNullByDefault - @ParametersNotNullByDefault - DatabaseConfig databaseConfig = - new AndroidDatabaseConfig(dbDir, keyDir); - return databaseConfig; + return new AndroidDatabaseConfig(dbDir, keyDir); } @Provides diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java index 1f7305371..671b6cb6a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java @@ -76,8 +76,8 @@ public class ConfigControllerImpl implements ConfigController { @Override public boolean accountExists() { - String hex = getEncryptedDatabaseKey(); - return hex != null && databaseConfig.databaseExists(); + return getEncryptedDatabaseKey() != null && + databaseConfig.getDatabaseDirectory().isDirectory(); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SignInReminderReceiver.java b/briar-android/src/main/java/org/briarproject/briar/android/login/SignInReminderReceiver.java index cf1edaae6..559757979 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/SignInReminderReceiver.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/SignInReminderReceiver.java @@ -51,7 +51,8 @@ public class SignInReminderReceiver extends BroadcastReceiver { if (action == null) return; if (action.equals(ACTION_BOOT_COMPLETED) || action.equals(ACTION_MY_PACKAGE_REPLACED)) { - if (databaseConfig.databaseExists()) { + // TODO: Use account manager to check whether account exists + if (databaseConfig.getDatabaseDirectory().isDirectory()) { SharedPreferences prefs = app.getDefaultSharedPreferences(); if (prefs.getBoolean(NOTIFY_SIGN_IN, true)) { showSignInNotification(ctx); From 233af699092ec3544990ed3258d0b7f5bb08e642 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 26 Jul 2018 17:09:09 +0100 Subject: [PATCH 05/18] Add TODOs. --- .../briarproject/bramble/plugin/tor/CircumventionProvider.java | 2 ++ .../bramble/plugin/tor/CircumventionProviderImpl.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProvider.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProvider.java index c1acfff7e..3625e206e 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProvider.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProvider.java @@ -4,6 +4,8 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor; import java.util.List; +// TODO: Create a module for this so it doesn't have to be public + public interface CircumventionProvider { /** diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java index 6a9999b9c..bf194fa4e 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tor/CircumventionProviderImpl.java @@ -16,6 +16,8 @@ import java.util.Set; import javax.annotation.Nullable; import javax.inject.Inject; +// TODO: Create a module for this so it doesn't need to be public + public class CircumventionProviderImpl implements CircumventionProvider { private final static String BRIDGE_FILE_NAME = "bridges"; From 1edf2bfa753f14ccaf64f088725fc1d523576ea4 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 26 Jul 2018 17:13:08 +0100 Subject: [PATCH 06/18] Move account deletion into AccountManager. --- .idea/runConfigurations/All_tests.xml | 1 + bramble-android/build.gradle | 8 ++ .../bramble/BrambleAndroidModule.java | 2 + .../account/AndroidAccountManager.java | 96 +++++++++++++++++++ .../bramble/account/AndroidAccountModule.java | 18 ++++ .../bramble/util/AndroidUtils.java | 25 ----- .../account/AndroidAccountManagerTest.java | 84 ++++++++++++++++ .../bramble/api/account/AccountManager.java | 4 + .../bramble/BrambleCoreModule.java | 2 - .../bramble/account/AccountManagerImpl.java | 14 +++ .../android/controller/ConfigController.java | 4 +- .../controller/ConfigControllerImpl.java | 58 +++-------- .../briar/android/login/PasswordActivity.java | 2 +- .../android/login/PasswordControllerImpl.java | 8 +- .../android/login/SetupControllerImpl.java | 8 +- .../android/panic/PanicResponderActivity.java | 2 +- .../android/splash/SplashScreenActivity.java | 2 +- .../controller/ConfigControllerImplTest.java | 49 ---------- .../login/PasswordControllerImplTest.java | 21 +--- .../login/SetupControllerImplTest.java | 12 +-- 20 files changed, 252 insertions(+), 168 deletions(-) create mode 100644 bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java create mode 100644 bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountModule.java create mode 100644 bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java delete mode 100644 briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java diff --git a/.idea/runConfigurations/All_tests.xml b/.idea/runConfigurations/All_tests.xml index 1882b817b..71857d973 100644 --- a/.idea/runConfigurations/All_tests.xml +++ b/.idea/runConfigurations/All_tests.xml @@ -21,6 +21,7 @@ diff --git a/bramble-android/build.gradle b/bramble-android/build.gradle index fe202931d..a07147eb2 100644 --- a/bramble-android/build.gradle +++ b/bramble-android/build.gradle @@ -34,6 +34,14 @@ dependencies { compileOnly 'javax.annotation:jsr250-api:1.0' + testImplementation project(path: ':bramble-api', configuration: 'testOutput') + testImplementation 'junit:junit:4.12' + testImplementation "org.jmock:jmock:2.8.2" + testImplementation "org.jmock:jmock-junit4:2.8.2" + testImplementation "org.jmock:jmock-legacy:2.8.2" + testImplementation "org.hamcrest:hamcrest-library:1.3" + testImplementation "org.hamcrest:hamcrest-core:1.3" + androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput') androidTestImplementation project(path: ':bramble-core', configuration: 'testOutput') androidTestImplementation 'com.android.support.test:runner:1.0.2' diff --git a/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java b/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java index cb563508a..d2e2979b6 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java @@ -2,6 +2,7 @@ package org.briarproject.bramble; import android.app.Application; +import org.briarproject.bramble.account.AndroidAccountModule; import org.briarproject.bramble.plugin.tor.CircumventionProvider; import org.briarproject.bramble.plugin.tor.CircumventionProviderImpl; import org.briarproject.bramble.system.AndroidSystemModule; @@ -12,6 +13,7 @@ import dagger.Module; import dagger.Provides; @Module(includes = { + AndroidAccountModule.class, AndroidSystemModule.class }) public class BrambleAndroidModule { diff --git a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java new file mode 100644 index 000000000..5fcaff509 --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java @@ -0,0 +1,96 @@ +package org.briarproject.bramble.account; + +import android.app.Application; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.util.IoUtils; + +import java.io.File; +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +class AndroidAccountManager extends AccountManagerImpl + implements AccountManager { + + private static final Logger LOG = + Logger.getLogger(AndroidAccountManager.class.getName()); + + private static final String PREF_DB_KEY = "key"; + + private final SharedPreferences briarPrefs; + private final Context appContext; + + @Inject + AndroidAccountManager(DatabaseConfig databaseConfig, + SharedPreferences briarPrefs, Application app) { + super(databaseConfig); + this.briarPrefs = briarPrefs; + appContext = app.getApplicationContext(); + } + + @Override + @Nullable + public String getEncryptedDatabaseKey() { + String key = getDatabaseKeyFromPreferences(); + if (key == null) key = super.getEncryptedDatabaseKey(); + else migrateDatabaseKeyToFile(key); + return key; + } + + @Nullable + private String getDatabaseKeyFromPreferences() { + String key = briarPrefs.getString(PREF_DB_KEY, null); + if (key == null) LOG.info("No database key in preferences"); + else LOG.info("Found database key in preferences"); + return key; + } + + private void migrateDatabaseKeyToFile(String key) { + if (storeEncryptedDatabaseKey(key)) { + if (briarPrefs.edit().remove(PREF_DB_KEY).commit()) + LOG.info("Database key migrated to file"); + else LOG.warning("Database key not removed from preferences"); + } else { + LOG.warning("Database key not migrated to file"); + } + } + + @Override + public void deleteAccount() { + super.deleteAccount(); + SharedPreferences defaultPrefs = + PreferenceManager.getDefaultSharedPreferences(appContext); + deleteAppData(briarPrefs, defaultPrefs); + } + + private void deleteAppData(SharedPreferences... clear) { + // Clear and commit shared preferences + for (SharedPreferences prefs : clear) { + if (!prefs.edit().clear().commit()) + LOG.warning("Could not clear shared preferences"); + } + // Delete files, except lib and shared_prefs directories + File dataDir = new File(appContext.getApplicationInfo().dataDir); + File[] children = dataDir.listFiles(); + if (children == null) { + LOG.warning("Could not list files in app data dir"); + } else { + for (File child : children) { + String name = child.getName(); + if (!name.equals("lib") && !name.equals("shared_prefs")) { + IoUtils.deleteFileOrDir(child); + } + } + } + // Recreate the cache dir as some OpenGL drivers expect it to exist + if (!new File(dataDir, "cache").mkdir()) + LOG.warning("Could not recreate cache dir"); + } + +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountModule.java b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountModule.java new file mode 100644 index 000000000..4e74ef9ea --- /dev/null +++ b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountModule.java @@ -0,0 +1,18 @@ +package org.briarproject.bramble.account; + +import org.briarproject.bramble.api.account.AccountManager; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class AndroidAccountModule { + + @Provides + @Singleton + AccountManager provideAccountManager(AndroidAccountManager accountManager) { + return accountManager; + } +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java b/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java index 9f9dd972d..5c0d073bd 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/util/AndroidUtils.java @@ -3,7 +3,6 @@ package org.briarproject.bramble.util; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.content.Context; -import android.content.SharedPreferences; import android.os.Build; import android.provider.Settings; @@ -58,30 +57,6 @@ public class AndroidUtils { && !address.equals(FAKE_BLUETOOTH_ADDRESS); } - public static void deleteAppData(Context ctx, SharedPreferences... clear) { - // Clear and commit shared preferences - for (SharedPreferences prefs : clear) { - if (!prefs.edit().clear().commit()) - LOG.warning("Could not clear shared preferences"); - } - // Delete files, except lib and shared_prefs directories - File dataDir = new File(ctx.getApplicationInfo().dataDir); - File[] children = dataDir.listFiles(); - if (children == null) { - LOG.warning("Could not list files in app data dir"); - } else { - for (File child : children) { - String name = child.getName(); - if (!name.equals("lib") && !name.equals("shared_prefs")) { - IoUtils.deleteFileOrDir(child); - } - } - } - // Recreate the cache dir as some OpenGL drivers expect it to exist - if (!new File(dataDir, "cache").mkdir()) - LOG.warning("Could not recreate cache dir"); - } - public static File getReportDir(Context ctx) { return ctx.getDir(STORED_REPORTS, MODE_PRIVATE); } diff --git a/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java b/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java new file mode 100644 index 000000000..7e529b698 --- /dev/null +++ b/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java @@ -0,0 +1,84 @@ +package org.briarproject.bramble.account; + +import android.app.Application; +import android.content.SharedPreferences; + +import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.test.BrambleMockTestCase; +import org.jmock.Expectations; +import org.jmock.lib.legacy.ClassImposteriser; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; +import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; +import static org.briarproject.bramble.test.TestUtils.getRandomBytes; +import static org.briarproject.bramble.test.TestUtils.getTestDirectory; +import static org.briarproject.bramble.util.StringUtils.toHexString; + +public class AndroidAccountManagerTest extends BrambleMockTestCase { + + private final SharedPreferences prefs = + context.mock(SharedPreferences.class); + private final DatabaseConfig databaseConfig = + context.mock(DatabaseConfig.class); + private final SharedPreferences.Editor + editor = context.mock(SharedPreferences.Editor.class); + private final Application app; + + private final String encryptedKeyHex = toHexString(getRandomBytes(123)); + private final File testDir = getTestDirectory(); + private final File keyDir = new File(testDir, "key"); + private final File keyFile = new File(keyDir, "db.key"); + private final File keyBackupFile = new File(keyDir, "db.key.bak"); + + private AndroidAccountManager accountManager; + + public AndroidAccountManagerTest() { + context.setImposteriser(ClassImposteriser.INSTANCE); + app = context.mock(Application.class); + } + + @Before + public void setUp() { + context.checking(new Expectations() {{ + allowing(databaseConfig).getDatabaseKeyDirectory(); + will(returnValue(keyDir)); + allowing(app).getApplicationContext(); + will(returnValue(app)); + }}); + accountManager = new AndroidAccountManager(databaseConfig, prefs, app); + } + + @Test + public void testDbKeyIsMigratedFromPreferencesToFile() { + context.checking(new Expectations() {{ + oneOf(prefs).getString("key", null); + will(returnValue(encryptedKeyHex)); + oneOf(prefs).edit(); + will(returnValue(editor)); + oneOf(editor).remove("key"); + will(returnValue(editor)); + oneOf(editor).commit(); + will(returnValue(true)); + }}); + + assertFalse(keyFile.exists()); + assertFalse(keyBackupFile.exists()); + + assertEquals(encryptedKeyHex, accountManager.getEncryptedDatabaseKey()); + + assertTrue(keyFile.exists()); + assertTrue(keyBackupFile.exists()); + } + + @After + public void tearDown() { + deleteTestDirectory(testDir); + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java index e1efc91dc..d0a39f216 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java @@ -19,4 +19,8 @@ public interface AccountManager { String getEncryptedDatabaseKey(); boolean storeEncryptedDatabaseKey(String hex); + + boolean accountExists(); + + void deleteAccount(); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/BrambleCoreModule.java b/bramble-core/src/main/java/org/briarproject/bramble/BrambleCoreModule.java index d817c6d57..07bc14eea 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/BrambleCoreModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/BrambleCoreModule.java @@ -1,6 +1,5 @@ package org.briarproject.bramble; -import org.briarproject.bramble.account.AccountModule; import org.briarproject.bramble.client.ClientModule; import org.briarproject.bramble.contact.ContactModule; import org.briarproject.bramble.crypto.CryptoExecutorModule; @@ -27,7 +26,6 @@ import org.briarproject.bramble.versioning.VersioningModule; import dagger.Module; @Module(includes = { - AccountModule.class, ClientModule.class, ContactModule.class, CryptoModule.class, diff --git a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java index cbc813d71..17bfa3c88 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java @@ -5,6 +5,7 @@ import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.util.IoUtils; import java.io.BufferedReader; import java.io.File; @@ -137,4 +138,17 @@ class AccountManagerImpl implements AccountManager { out.flush(); out.close(); } + + @Override + public boolean accountExists() { + return getEncryptedDatabaseKey() != null + && databaseConfig.getDatabaseDirectory().isDirectory(); + } + + @Override + public void deleteAccount() { + LOG.info("Deleting account"); + IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory()); + IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory()); + } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigController.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigController.java index e19452a9c..decc39a03 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigController.java @@ -1,7 +1,5 @@ package org.briarproject.briar.android.controller; -import android.content.Context; - import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import javax.annotation.Nullable; @@ -14,7 +12,7 @@ public interface ConfigController { boolean storeEncryptedDatabaseKey(String hex); - void deleteAccount(Context ctx); + void deleteAccount(); boolean accountExists(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java index 671b6cb6a..bd76c558c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java @@ -1,64 +1,32 @@ package org.briarproject.briar.android.controller; -import android.content.Context; -import android.content.SharedPreferences; -import android.support.v7.preference.PreferenceManager; +import android.util.Log; import org.briarproject.bramble.api.account.AccountManager; -import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.util.AndroidUtils; - -import java.util.logging.Logger; import javax.annotation.Nullable; import javax.inject.Inject; +// TODO: Remove this class, which just delegates to AccountManager + @NotNullByDefault public class ConfigControllerImpl implements ConfigController { - private static final Logger LOG = - Logger.getLogger(ConfigControllerImpl.class.getName()); - - private static final String PREF_DB_KEY = "key"; - - private final SharedPreferences briarPrefs; protected final AccountManager accountManager; - protected final DatabaseConfig databaseConfig; @Inject - public ConfigControllerImpl(SharedPreferences briarPrefs, - AccountManager accountManager, DatabaseConfig databaseConfig) { - this.briarPrefs = briarPrefs; + public ConfigControllerImpl(AccountManager accountManager) { + // TODO: Remove + Log.i(getClass().getName(), "Using account manager " + + accountManager.getClass().getName()); this.accountManager = accountManager; - this.databaseConfig = databaseConfig; } @Override @Nullable public String getEncryptedDatabaseKey() { - String key = getDatabaseKeyFromPreferences(); - if (key == null) key = accountManager.getEncryptedDatabaseKey(); - else migrateDatabaseKeyToFile(key); - return key; - } - - @Nullable - private String getDatabaseKeyFromPreferences() { - String key = briarPrefs.getString(PREF_DB_KEY, null); - if (key == null) LOG.info("No database key in preferences"); - else LOG.info("Found database key in preferences"); - return key; - } - - private void migrateDatabaseKeyToFile(String key) { - if (accountManager.storeEncryptedDatabaseKey(key)) { - if (briarPrefs.edit().remove(PREF_DB_KEY).commit()) - LOG.info("Database key migrated to file"); - else LOG.warning("Database key not removed from preferences"); - } else { - LOG.warning("Database key not migrated to file"); - } + return accountManager.getEncryptedDatabaseKey(); } @Override @@ -67,17 +35,13 @@ public class ConfigControllerImpl implements ConfigController { } @Override - public void deleteAccount(Context ctx) { - LOG.info("Deleting account"); - SharedPreferences defaultPrefs = - PreferenceManager.getDefaultSharedPreferences(ctx); - AndroidUtils.deleteAppData(ctx, briarPrefs, defaultPrefs); + public void deleteAccount() { + accountManager.deleteAccount(); } @Override public boolean accountExists() { - return getEncryptedDatabaseKey() != null && - databaseConfig.getDatabaseDirectory().isDirectory(); + return accountManager.hasDatabaseKey(); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java index 5504132b4..6de30bf7f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java @@ -105,7 +105,7 @@ public class PasswordActivity extends BaseActivity { } private void deleteAccount() { - passwordController.deleteAccount(this); + passwordController.deleteAccount(); Localizer.reinitialize(); UiUtils.setTheme(this, getString(R.string.pref_theme_light_value)); setResult(RESULT_CANCELED); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java index 5a3cd5b8d..23f479450 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java @@ -1,13 +1,10 @@ package org.briarproject.briar.android.login; -import android.content.SharedPreferences; - import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.api.crypto.SecretKey; -import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.util.StringUtils; import org.briarproject.briar.android.controller.ConfigControllerImpl; @@ -33,11 +30,10 @@ public class PasswordControllerImpl extends ConfigControllerImpl private final PasswordStrengthEstimator strengthEstimator; @Inject - PasswordControllerImpl(SharedPreferences briarPrefs, - AccountManager accountManager, DatabaseConfig databaseConfig, + PasswordControllerImpl(AccountManager accountManager, @CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto, PasswordStrengthEstimator strengthEstimator) { - super(briarPrefs, accountManager, databaseConfig); + super(accountManager); this.cryptoExecutor = cryptoExecutor; this.crypto = crypto; this.strengthEstimator = strengthEstimator; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java index a2395d894..c4ce4ae2c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java @@ -1,6 +1,5 @@ package org.briarproject.briar.android.login; -import android.content.SharedPreferences; import android.support.annotation.Nullable; import org.briarproject.bramble.api.account.AccountManager; @@ -8,7 +7,6 @@ import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.api.crypto.SecretKey; -import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; @@ -33,13 +31,11 @@ public class SetupControllerImpl extends PasswordControllerImpl private volatile SetupActivity setupActivity; @Inject - SetupControllerImpl(SharedPreferences briarPrefs, - AccountManager accountManager, DatabaseConfig databaseConfig, + SetupControllerImpl(AccountManager accountManager, @CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto, PasswordStrengthEstimator strengthEstimator, IdentityManager identityManager) { - super(briarPrefs, accountManager, databaseConfig, cryptoExecutor, - crypto, strengthEstimator); + super(accountManager, cryptoExecutor, crypto, strengthEstimator); this.identityManager = identityManager; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java index dd122e149..fb2cd920f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java @@ -94,7 +94,7 @@ public class PanicResponderActivity extends BriarActivity { private void deleteAllData() { androidExecutor.runOnBackgroundThread(() -> { - configController.deleteAccount(PanicResponderActivity.this); + configController.deleteAccount(); // TODO somehow delete/shred the database more thoroughly PanicResponder.deleteAllAppData(PanicResponderActivity.this); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java index d207508a4..8f3dd2882 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java @@ -69,7 +69,7 @@ public class SplashScreenActivity extends BaseActivity { startActivity(new Intent(this, OpenDatabaseActivity.class)); } else { LOG.info("Account does not exist"); - configController.deleteAccount(this); + configController.deleteAccount(); startActivity(new Intent(this, SetupActivity.class)); } } diff --git a/briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java deleted file mode 100644 index 06f1165ab..000000000 --- a/briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.briarproject.briar.android.controller; - -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; - -import org.briarproject.bramble.api.account.AccountManager; -import org.briarproject.bramble.api.db.DatabaseConfig; -import org.briarproject.bramble.test.BrambleMockTestCase; -import org.jmock.Expectations; -import org.junit.Test; - -import static junit.framework.Assert.assertEquals; -import static org.briarproject.bramble.test.TestUtils.getRandomBytes; -import static org.briarproject.bramble.util.StringUtils.toHexString; - -public class ConfigControllerImplTest extends BrambleMockTestCase { - - private final SharedPreferences prefs = - context.mock(SharedPreferences.class); - private final AccountManager accountManager = - context.mock(AccountManager.class); - private final DatabaseConfig databaseConfig = - context.mock(DatabaseConfig.class); - private final Editor editor = context.mock(Editor.class); - - private final String encryptedKeyHex = toHexString(getRandomBytes(123)); - - @Test - public void testDbKeyIsMigratedFromPreferencesToFile() { - context.checking(new Expectations() {{ - oneOf(prefs).getString("key", null); - will(returnValue(encryptedKeyHex)); - oneOf(accountManager).storeEncryptedDatabaseKey(encryptedKeyHex); - will(returnValue(true)); - oneOf(prefs).edit(); - will(returnValue(editor)); - oneOf(editor).remove("key"); - will(returnValue(editor)); - oneOf(editor).commit(); - will(returnValue(true)); - }}); - - ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager, - databaseConfig); - - assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey()); - } - -} diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java index 9c64083cd..3c55a199c 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java @@ -1,11 +1,8 @@ package org.briarproject.briar.android.login; -import android.content.SharedPreferences; - import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; -import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.ImmediateExecutor; import org.jmock.Expectations; @@ -22,12 +19,8 @@ import static org.briarproject.bramble.util.StringUtils.toHexString; public class PasswordControllerImplTest extends BrambleMockTestCase { - private final SharedPreferences briarPrefs = - context.mock(SharedPreferences.class); private final AccountManager accountManager = context.mock(AccountManager.class); - private final DatabaseConfig databaseConfig = - context.mock(DatabaseConfig.class); private final CryptoComponent crypto = context.mock(CryptoComponent.class); private final PasswordStrengthEstimator estimator = context.mock(PasswordStrengthEstimator.class); @@ -46,8 +39,6 @@ public class PasswordControllerImplTest extends BrambleMockTestCase { public void testChangePasswordReturnsTrue() { context.checking(new Expectations() {{ // Look up the encrypted DB key - oneOf(briarPrefs).getString("key", null); - will(returnValue(null)); oneOf(accountManager).getEncryptedDatabaseKey(); will(returnValue(oldEncryptedKeyHex)); // Decrypt and re-encrypt the key @@ -60,9 +51,8 @@ public class PasswordControllerImplTest extends BrambleMockTestCase { will(returnValue(true)); }}); - PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs, - accountManager, databaseConfig, cryptoExecutor, crypto, - estimator); + PasswordControllerImpl p = new PasswordControllerImpl(accountManager, + cryptoExecutor, crypto, estimator); AtomicBoolean capturedResult = new AtomicBoolean(false); p.changePassword(oldPassword, newPassword, capturedResult::set); @@ -73,8 +63,6 @@ public class PasswordControllerImplTest extends BrambleMockTestCase { public void testChangePasswordReturnsFalseIfOldPasswordIsWrong() { context.checking(new Expectations() {{ // Look up the encrypted DB key - oneOf(briarPrefs).getString("key", null); - will(returnValue(null)); oneOf(accountManager).getEncryptedDatabaseKey(); will(returnValue(oldEncryptedKeyHex)); // Try to decrypt the key - the password is wrong @@ -82,9 +70,8 @@ public class PasswordControllerImplTest extends BrambleMockTestCase { will(returnValue(null)); }}); - PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs, - accountManager, databaseConfig, cryptoExecutor, crypto, - estimator); + PasswordControllerImpl p = new PasswordControllerImpl(accountManager, + cryptoExecutor, crypto, estimator); AtomicBoolean capturedResult = new AtomicBoolean(true); p.changePassword(oldPassword, newPassword, capturedResult::set); diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java index 4671bb1c4..98d342389 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java @@ -1,12 +1,9 @@ package org.briarproject.briar.android.login; -import android.content.SharedPreferences; - import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.api.crypto.SecretKey; -import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.test.BrambleMockTestCase; @@ -28,12 +25,8 @@ import static org.briarproject.bramble.util.StringUtils.toHexString; public class SetupControllerImplTest extends BrambleMockTestCase { - private final SharedPreferences briarPrefs = - context.mock(SharedPreferences.class); private final AccountManager accountManager = context.mock(AccountManager.class); - private final DatabaseConfig databaseConfig = - context.mock(DatabaseConfig.class); private final CryptoComponent crypto = context.mock(CryptoComponent.class); private final PasswordStrengthEstimator estimator = context.mock(PasswordStrengthEstimator.class); @@ -84,9 +77,8 @@ public class SetupControllerImplTest extends BrambleMockTestCase { oneOf(accountManager).setDatabaseKey(key); }}); - SetupControllerImpl s = new SetupControllerImpl(briarPrefs, - accountManager, databaseConfig, cryptoExecutor, crypto, - estimator, identityManager); + SetupControllerImpl s = new SetupControllerImpl(accountManager, + cryptoExecutor, crypto, estimator, identityManager); s.setSetupActivity(setupActivity); AtomicBoolean called = new AtomicBoolean(false); From f9d8c720ecb1168f237387e011fb82df7ba5e656 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 26 Jul 2018 17:34:51 +0100 Subject: [PATCH 07/18] Remove ConfigController. --- .../android/activity/ActivityModule.java | 9 ---- .../android/controller/ConfigController.java | 21 -------- .../controller/ConfigControllerImpl.java | 51 ------------------- .../briar/android/login/PasswordActivity.java | 8 ++- .../android/login/PasswordController.java | 3 +- .../android/login/PasswordControllerImpl.java | 12 ++--- .../briar/android/login/SetupActivity.java | 7 ++- .../android/login/SetupControllerImpl.java | 2 +- .../android/panic/PanicResponderActivity.java | 6 +-- .../android/splash/SplashScreenActivity.java | 10 ++-- 10 files changed, 27 insertions(+), 102 deletions(-) delete mode 100644 briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigController.java delete mode 100644 briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityModule.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityModule.java index 2651833f1..b21d07232 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityModule.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityModule.java @@ -4,8 +4,6 @@ import android.app.Activity; import org.briarproject.briar.android.controller.BriarController; import org.briarproject.briar.android.controller.BriarControllerImpl; -import org.briarproject.briar.android.controller.ConfigController; -import org.briarproject.briar.android.controller.ConfigControllerImpl; import org.briarproject.briar.android.controller.DbController; import org.briarproject.briar.android.controller.DbControllerImpl; import org.briarproject.briar.android.login.PasswordController; @@ -48,13 +46,6 @@ public class ActivityModule { return setupController; } - @ActivityScope - @Provides - ConfigController provideConfigController( - ConfigControllerImpl configController) { - return configController; - } - @ActivityScope @Provides PasswordController providePasswordController( diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigController.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigController.java deleted file mode 100644 index decc39a03..000000000 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigController.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.briarproject.briar.android.controller; - -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; - -import javax.annotation.Nullable; - -@NotNullByDefault -public interface ConfigController { - - @Nullable - String getEncryptedDatabaseKey(); - - boolean storeEncryptedDatabaseKey(String hex); - - void deleteAccount(); - - boolean accountExists(); - - boolean accountSignedIn(); - -} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java deleted file mode 100644 index bd76c558c..000000000 --- a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.briarproject.briar.android.controller; - -import android.util.Log; - -import org.briarproject.bramble.api.account.AccountManager; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; - -import javax.annotation.Nullable; -import javax.inject.Inject; - -// TODO: Remove this class, which just delegates to AccountManager - -@NotNullByDefault -public class ConfigControllerImpl implements ConfigController { - - protected final AccountManager accountManager; - - @Inject - public ConfigControllerImpl(AccountManager accountManager) { - // TODO: Remove - Log.i(getClass().getName(), "Using account manager " - + accountManager.getClass().getName()); - this.accountManager = accountManager; - } - - @Override - @Nullable - public String getEncryptedDatabaseKey() { - return accountManager.getEncryptedDatabaseKey(); - } - - @Override - public boolean storeEncryptedDatabaseKey(String hex) { - return accountManager.storeEncryptedDatabaseKey(hex); - } - - @Override - public void deleteAccount() { - accountManager.deleteAccount(); - } - - @Override - public boolean accountExists() { - return accountManager.hasDatabaseKey(); - } - - @Override - public boolean accountSignedIn() { - return accountManager.hasDatabaseKey(); - } -} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java index 6de30bf7f..537d00d08 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java @@ -12,6 +12,7 @@ import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.briar.R; import org.briarproject.briar.android.Localizer; import org.briarproject.briar.android.activity.ActivityComponent; @@ -31,6 +32,9 @@ import static android.view.View.VISIBLE; public class PasswordActivity extends BaseActivity { + @Inject + AccountManager accountManager; + @Inject PasswordController passwordController; @@ -48,7 +52,7 @@ public class PasswordActivity extends BaseActivity { // fade-in after splash screen instead of default animation overridePendingTransition(R.anim.fade_in, R.anim.fade_out); - if (!passwordController.accountExists()) { + if (!accountManager.accountExists()) { deleteAccount(); return; } @@ -105,7 +109,7 @@ public class PasswordActivity extends BaseActivity { } private void deleteAccount() { - passwordController.deleteAccount(); + accountManager.deleteAccount(); Localizer.reinitialize(); UiUtils.setTheme(this, getString(R.string.pref_theme_light_value)); setResult(RESULT_CANCELED); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordController.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordController.java index ec3cb7ed7..6ad1d26b5 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordController.java @@ -1,11 +1,10 @@ package org.briarproject.briar.android.login; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.briar.android.controller.ConfigController; import org.briarproject.briar.android.controller.handler.ResultHandler; @NotNullByDefault -public interface PasswordController extends ConfigController { +public interface PasswordController { float estimatePasswordStrength(String password); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java index 23f479450..53cc1b3bd 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java @@ -7,7 +7,6 @@ import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.util.StringUtils; -import org.briarproject.briar.android.controller.ConfigControllerImpl; import org.briarproject.briar.android.controller.handler.ResultHandler; import java.util.concurrent.Executor; @@ -19,12 +18,12 @@ import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.now; @NotNullByDefault -public class PasswordControllerImpl extends ConfigControllerImpl - implements PasswordController { +public class PasswordControllerImpl implements PasswordController { private static final Logger LOG = Logger.getLogger(PasswordControllerImpl.class.getName()); + protected final AccountManager accountManager; protected final Executor cryptoExecutor; protected final CryptoComponent crypto; private final PasswordStrengthEstimator strengthEstimator; @@ -33,7 +32,7 @@ public class PasswordControllerImpl extends ConfigControllerImpl PasswordControllerImpl(AccountManager accountManager, @CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto, PasswordStrengthEstimator strengthEstimator) { - super(accountManager); + this.accountManager = accountManager; this.cryptoExecutor = cryptoExecutor; this.crypto = crypto; this.strengthEstimator = strengthEstimator; @@ -70,13 +69,14 @@ public class PasswordControllerImpl extends ConfigControllerImpl } else { String hex = encryptDatabaseKey(new SecretKey(key), newPassword); - resultHandler.onResult(storeEncryptedDatabaseKey(hex)); + boolean stored = accountManager.storeEncryptedDatabaseKey(hex); + resultHandler.onResult(stored); } }); } private byte[] getEncryptedKey() { - String hex = getEncryptedDatabaseKey(); + String hex = accountManager.getEncryptedDatabaseKey(); if (hex == null) throw new IllegalStateException("Encrypted database key is null"); return StringUtils.fromHexString(hex); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupActivity.java index f91c57512..e38cfeb0c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupActivity.java @@ -4,6 +4,7 @@ import android.annotation.TargetApi; import android.content.Intent; import android.os.Bundle; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; @@ -25,6 +26,9 @@ public class SetupActivity extends BaseActivity private static final String STATE_KEY_AUTHOR_NAME = "authorName"; private static final String STATE_KEY_PASSWORD = "password"; + @Inject + AccountManager accountManager; + @Inject SetupController setupController; @@ -39,8 +43,7 @@ public class SetupActivity extends BaseActivity setContentView(R.layout.activity_fragment_container); if (state == null) { - if (setupController.accountExists()) - throw new AssertionError(); + if (accountManager.accountExists()) throw new AssertionError(); showInitialFragment(AuthorNameFragment.newInstance()); } else { authorName = state.getString(STATE_KEY_AUTHOR_NAME); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java index c4ce4ae2c..a29d2bc76 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java @@ -110,7 +110,7 @@ public class SetupControllerImpl extends PasswordControllerImpl identityManager.registerLocalAuthor(localAuthor); SecretKey key = crypto.generateSecretKey(); String hex = encryptDatabaseKey(key, password); - storeEncryptedDatabaseKey(hex); + accountManager.storeEncryptedDatabaseKey(hex); accountManager.setDatabaseKey(key); resultHandler.onResult(null); }); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java index fb2cd920f..9d64d1500 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/panic/PanicResponderActivity.java @@ -7,10 +7,10 @@ import android.os.Build; import android.os.Bundle; import android.support.v7.preference.PreferenceManager; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BriarActivity; -import org.briarproject.briar.android.controller.ConfigController; import org.iilab.IilabEngineeringRSA2048Pin; import java.util.logging.Logger; @@ -33,7 +33,7 @@ public class PanicResponderActivity extends BriarActivity { Logger.getLogger(PanicResponderActivity.class.getName()); @Inject - protected ConfigController configController; + protected AccountManager accountManager; @Inject protected AndroidExecutor androidExecutor; @@ -94,7 +94,7 @@ public class PanicResponderActivity extends BriarActivity { private void deleteAllData() { androidExecutor.runOnBackgroundThread(() -> { - configController.deleteAccount(); + accountManager.deleteAccount(); // TODO somehow delete/shred the database more thoroughly PanicResponder.deleteAllAppData(PanicResponderActivity.this); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java index 8f3dd2882..e878d2376 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java @@ -7,11 +7,11 @@ import android.os.Handler; import android.support.v7.preference.PreferenceManager; import android.transition.Fade; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BaseActivity; -import org.briarproject.briar.android.controller.ConfigController; import org.briarproject.briar.android.login.OpenDatabaseActivity; import org.briarproject.briar.android.login.SetupActivity; @@ -27,7 +27,7 @@ public class SplashScreenActivity extends BaseActivity { Logger.getLogger(SplashScreenActivity.class.getName()); @Inject - protected ConfigController configController; + protected AccountManager accountManager; @Inject protected AndroidExecutor androidExecutor; @@ -43,7 +43,7 @@ public class SplashScreenActivity extends BaseActivity { setContentView(R.layout.splash); - if (configController.accountSignedIn()) { + if (accountManager.hasDatabaseKey()) { startActivity(new Intent(this, OpenDatabaseActivity.class)); finish(); } else { @@ -64,12 +64,12 @@ public class SplashScreenActivity extends BaseActivity { LOG.info("Expired"); startActivity(new Intent(this, ExpiredActivity.class)); } else { - if (configController.accountExists()) { + if (accountManager.accountExists()) { LOG.info("Account exists"); startActivity(new Intent(this, OpenDatabaseActivity.class)); } else { LOG.info("Account does not exist"); - configController.deleteAccount(); + accountManager.deleteAccount(); startActivity(new Intent(this, SetupActivity.class)); } } From 4a9977fa58a67565818e3c1f44ba28942408fbe1 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 26 Jul 2018 17:38:26 +0100 Subject: [PATCH 08/18] Use account manager to check whether account exists. --- .../briar/android/login/SignInReminderReceiver.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SignInReminderReceiver.java b/briar-android/src/main/java/org/briarproject/briar/android/login/SignInReminderReceiver.java index 559757979..0ed79eddf 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/SignInReminderReceiver.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/SignInReminderReceiver.java @@ -10,7 +10,7 @@ import android.content.SharedPreferences; import android.support.v4.app.NotificationCompat; import android.support.v4.content.ContextCompat; -import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.briar.R; import org.briarproject.briar.android.AndroidComponent; import org.briarproject.briar.android.BriarApplication; @@ -37,7 +37,7 @@ public class SignInReminderReceiver extends BroadcastReceiver { public static final String DISMISS_REMINDER = "dismissReminder"; @Inject - DatabaseConfig databaseConfig; + AccountManager accountManager; @Override public void onReceive(Context ctx, Intent intent) { @@ -51,8 +51,7 @@ public class SignInReminderReceiver extends BroadcastReceiver { if (action == null) return; if (action.equals(ACTION_BOOT_COMPLETED) || action.equals(ACTION_MY_PACKAGE_REPLACED)) { - // TODO: Use account manager to check whether account exists - if (databaseConfig.getDatabaseDirectory().isDirectory()) { + if (accountManager.accountExists()) { SharedPreferences prefs = app.getDefaultSharedPreferences(); if (prefs.getBoolean(NOTIFY_SIGN_IN, true)) { showSignInNotification(ctx); From 6ca0339da2977a7dded9b576efc8865067f31df1 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 27 Jul 2018 11:35:27 +0100 Subject: [PATCH 09/18] Move DB key management into account manager. --- .../account/AndroidAccountManager.java | 20 +++--- .../account/AndroidAccountManagerTest.java | 7 +- .../bramble/api/account/AccountManager.java | 13 ++-- .../bramble/account/AccountManagerImpl.java | 64 +++++++++++++++---- .../account/AccountManagerImplTest.java | 22 ++++--- .../android/login/PasswordController.java | 2 +- .../android/login/PasswordControllerImpl.java | 64 ++++--------------- .../android/login/SetupControllerImpl.java | 24 +++---- .../login/PasswordControllerImplTest.java | 35 ++-------- .../login/SetupControllerImplTest.java | 25 ++------ .../feed/FeedManagerIntegrationTest.java | 3 +- .../SimplexMessagingIntegrationTest.java | 4 +- .../briar/test/BriarIntegrationTest.java | 6 +- 13 files changed, 123 insertions(+), 166 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java index 5fcaff509..d792672c4 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java @@ -6,6 +6,7 @@ import android.content.SharedPreferences; import android.preference.PreferenceManager; import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.util.IoUtils; @@ -23,29 +24,29 @@ class AndroidAccountManager extends AccountManagerImpl private static final String PREF_DB_KEY = "key"; - private final SharedPreferences briarPrefs; + private final SharedPreferences prefs; private final Context appContext; @Inject AndroidAccountManager(DatabaseConfig databaseConfig, - SharedPreferences briarPrefs, Application app) { - super(databaseConfig); - this.briarPrefs = briarPrefs; + CryptoComponent crypto, SharedPreferences prefs, Application app) { + super(databaseConfig, crypto); + this.prefs = prefs; appContext = app.getApplicationContext(); } @Override @Nullable - public String getEncryptedDatabaseKey() { + protected String loadEncryptedDatabaseKey() { String key = getDatabaseKeyFromPreferences(); - if (key == null) key = super.getEncryptedDatabaseKey(); + if (key == null) key = super.loadEncryptedDatabaseKey(); else migrateDatabaseKeyToFile(key); return key; } @Nullable private String getDatabaseKeyFromPreferences() { - String key = briarPrefs.getString(PREF_DB_KEY, null); + String key = prefs.getString(PREF_DB_KEY, null); if (key == null) LOG.info("No database key in preferences"); else LOG.info("Found database key in preferences"); return key; @@ -53,7 +54,7 @@ class AndroidAccountManager extends AccountManagerImpl private void migrateDatabaseKeyToFile(String key) { if (storeEncryptedDatabaseKey(key)) { - if (briarPrefs.edit().remove(PREF_DB_KEY).commit()) + if (prefs.edit().remove(PREF_DB_KEY).commit()) LOG.info("Database key migrated to file"); else LOG.warning("Database key not removed from preferences"); } else { @@ -66,7 +67,7 @@ class AndroidAccountManager extends AccountManagerImpl super.deleteAccount(); SharedPreferences defaultPrefs = PreferenceManager.getDefaultSharedPreferences(appContext); - deleteAppData(briarPrefs, defaultPrefs); + deleteAppData(prefs, defaultPrefs); } private void deleteAppData(SharedPreferences... clear) { @@ -92,5 +93,4 @@ class AndroidAccountManager extends AccountManagerImpl if (!new File(dataDir, "cache").mkdir()) LOG.warning("Could not recreate cache dir"); } - } diff --git a/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java b/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java index 7e529b698..1922954a0 100644 --- a/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java +++ b/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java @@ -3,6 +3,7 @@ package org.briarproject.bramble.account; import android.app.Application; import android.content.SharedPreferences; +import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.test.BrambleMockTestCase; import org.jmock.Expectations; @@ -27,6 +28,7 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase { context.mock(SharedPreferences.class); private final DatabaseConfig databaseConfig = context.mock(DatabaseConfig.class); + private final CryptoComponent crypto = context.mock(CryptoComponent.class); private final SharedPreferences.Editor editor = context.mock(SharedPreferences.Editor.class); private final Application app; @@ -52,7 +54,8 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase { allowing(app).getApplicationContext(); will(returnValue(app)); }}); - accountManager = new AndroidAccountManager(databaseConfig, prefs, app); + accountManager = new AndroidAccountManager(databaseConfig, crypto, + prefs, app); } @Test @@ -71,7 +74,7 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase { assertFalse(keyFile.exists()); assertFalse(keyBackupFile.exists()); - assertEquals(encryptedKeyHex, accountManager.getEncryptedDatabaseKey()); + assertEquals(encryptedKeyHex, accountManager.loadEncryptedDatabaseKey()); assertTrue(keyFile.exists()); assertTrue(keyBackupFile.exists()); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java index d0a39f216..15d531220 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java @@ -13,14 +13,13 @@ public interface AccountManager { @Nullable SecretKey getDatabaseKey(); - void setDatabaseKey(SecretKey k); - - @Nullable - String getEncryptedDatabaseKey(); - - boolean storeEncryptedDatabaseKey(String hex); - boolean accountExists(); + boolean createAccount(String password); + void deleteAccount(); + + boolean signIn(String password); + + boolean changePassword(String oldPassword, String newPassword); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java index 17bfa3c88..4d076fd2e 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java @@ -1,6 +1,7 @@ package org.briarproject.bramble.account; 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.nullsafety.MethodsNotNullByDefault; @@ -20,6 +21,8 @@ import javax.inject.Inject; import static java.util.logging.Level.WARNING; import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.bramble.util.StringUtils.fromHexString; +import static org.briarproject.bramble.util.StringUtils.toHexString; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -32,14 +35,16 @@ class AccountManagerImpl implements AccountManager { private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak"; private final DatabaseConfig databaseConfig; + private final CryptoComponent crypto; private final File dbKeyFile, dbKeyBackupFile; @Nullable private volatile SecretKey databaseKey = null; @Inject - AccountManagerImpl(DatabaseConfig databaseConfig) { + AccountManagerImpl(DatabaseConfig databaseConfig, CryptoComponent crypto) { this.databaseConfig = databaseConfig; + this.crypto = crypto; File keyDir = databaseConfig.getDatabaseKeyDirectory(); dbKeyFile = new File(keyDir, DB_KEY_FILENAME); dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME); @@ -56,14 +61,8 @@ class AccountManagerImpl implements AccountManager { return databaseKey; } - @Override - public void setDatabaseKey(SecretKey k) { - databaseKey = k; - } - - @Override @Nullable - public String getEncryptedDatabaseKey() { + protected String loadEncryptedDatabaseKey() { String key = readDbKeyFromFile(dbKeyFile); if (key == null) { LOG.info("No database key in primary file"); @@ -94,8 +93,7 @@ class AccountManagerImpl implements AccountManager { } } - @Override - public boolean storeEncryptedDatabaseKey(String hex) { + protected boolean storeEncryptedDatabaseKey(String hex) { LOG.info("Storing database key in file"); // Create the directory if necessary if (databaseConfig.getDatabaseKeyDirectory().mkdirs()) @@ -141,14 +139,58 @@ class AccountManagerImpl implements AccountManager { @Override public boolean accountExists() { - return getEncryptedDatabaseKey() != null + return loadEncryptedDatabaseKey() != null && databaseConfig.getDatabaseDirectory().isDirectory(); } + @Override + public boolean createAccount(String password) { + SecretKey key = crypto.generateSecretKey(); + if (!encryptAndStoreDatabaseKey(key, password)) return false; + databaseKey = key; + return true; + } + + private boolean encryptAndStoreDatabaseKey(SecretKey key, String password) { + byte[] plaintext = key.getBytes(); + byte[] ciphertext = crypto.encryptWithPassword(plaintext, password); + return storeEncryptedDatabaseKey(toHexString(ciphertext)); + } + @Override public void deleteAccount() { LOG.info("Deleting account"); IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory()); IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory()); } + + @Override + public boolean signIn(String password) { + SecretKey key = loadAndDecryptDatabaseKey(password); + if (key == null) return false; + databaseKey = key; + return true; + } + + @Nullable + private SecretKey loadAndDecryptDatabaseKey(String password) { + String hex = loadEncryptedDatabaseKey(); + if (hex == null) { + LOG.warning("Failed to load encrypted database key"); + return null; + } + byte[] ciphertext = fromHexString(hex); + byte[] plaintext = crypto.decryptWithPassword(ciphertext, password); + if (plaintext == null) { + LOG.info("Failed to decrypt database key"); + return null; + } + return new SecretKey(plaintext); + } + + @Override + public boolean changePassword(String oldPassword, String newPassword) { + SecretKey key = loadAndDecryptDatabaseKey(oldPassword); + return key != null && encryptAndStoreDatabaseKey(key, newPassword); + } } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java index 7e1f6124d..e0a51898d 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java @@ -1,5 +1,6 @@ package org.briarproject.bramble.account; +import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.test.BrambleMockTestCase; import org.jmock.Expectations; @@ -29,6 +30,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase { private final DatabaseConfig databaseConfig = context.mock(DatabaseConfig.class); + private final CryptoComponent crypto = context.mock(CryptoComponent.class); private final byte[] encryptedKey = getRandomBytes(123); private final String encryptedKeyHex = toHexString(encryptedKey); @@ -46,7 +48,8 @@ public class AccountManagerImplTest extends BrambleMockTestCase { allowing(databaseConfig).getDatabaseKeyDirectory(); will(returnValue(keyDir)); }}); - accountManager = new AccountManagerImpl(databaseConfig); + assertTrue(keyDir.mkdirs()); + accountManager = new AccountManagerImpl(databaseConfig, crypto); } @Test @@ -60,7 +63,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase { assertFalse(keyBackupFile.exists()); assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); - assertEquals(encryptedKeyHex, accountManager.getEncryptedDatabaseKey()); + assertEquals(encryptedKeyHex, accountManager.loadEncryptedDatabaseKey()); assertTrue(keyFile.exists()); assertFalse(keyBackupFile.exists()); @@ -78,7 +81,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase { assertTrue(keyBackupFile.exists()); assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); - assertEquals(encryptedKeyHex, accountManager.getEncryptedDatabaseKey()); + assertEquals(encryptedKeyHex, accountManager.loadEncryptedDatabaseKey()); assertFalse(keyFile.exists()); assertTrue(keyBackupFile.exists()); @@ -90,7 +93,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase { assertFalse(keyFile.exists()); assertFalse(keyBackupFile.exists()); - assertNull(accountManager.getEncryptedDatabaseKey()); + assertNull(accountManager.loadEncryptedDatabaseKey()); assertFalse(keyFile.exists()); assertFalse(keyBackupFile.exists()); @@ -134,13 +137,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase { assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); } - @After - public void tearDown() { - deleteTestDirectory(testDir); - } - private void storeDatabaseKey(File f, String hex) throws IOException { - f.getParentFile().mkdirs(); FileOutputStream out = new FileOutputStream(f); out.write(hex.getBytes("UTF-8")); out.flush(); @@ -155,4 +152,9 @@ public class AccountManagerImplTest extends BrambleMockTestCase { reader.close(); return hex; } + + @After + public void tearDown() { + deleteTestDirectory(testDir); + } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordController.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordController.java index 6ad1d26b5..cef864152 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordController.java @@ -11,7 +11,7 @@ public interface PasswordController { void validatePassword(String password, ResultHandler resultHandler); - void changePassword(String password, String newPassword, + void changePassword(String oldPassword, String newPassword, ResultHandler resultHandler); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java index 53cc1b3bd..0ecf78475 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java @@ -1,40 +1,28 @@ package org.briarproject.briar.android.login; import org.briarproject.bramble.api.account.AccountManager; -import org.briarproject.bramble.api.crypto.CryptoComponent; -import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; -import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.util.StringUtils; import org.briarproject.briar.android.controller.handler.ResultHandler; import java.util.concurrent.Executor; -import java.util.logging.Logger; import javax.inject.Inject; -import static org.briarproject.bramble.util.LogUtils.logDuration; -import static org.briarproject.bramble.util.LogUtils.now; - @NotNullByDefault public class PasswordControllerImpl implements PasswordController { - private static final Logger LOG = - Logger.getLogger(PasswordControllerImpl.class.getName()); - protected final AccountManager accountManager; - protected final Executor cryptoExecutor; - protected final CryptoComponent crypto; + protected final Executor ioExecutor; private final PasswordStrengthEstimator strengthEstimator; @Inject PasswordControllerImpl(AccountManager accountManager, - @CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto, + @IoExecutor Executor ioExecutor, PasswordStrengthEstimator strengthEstimator) { this.accountManager = accountManager; - this.cryptoExecutor = cryptoExecutor; - this.crypto = crypto; + this.ioExecutor = ioExecutor; this.strengthEstimator = strengthEstimator; } @@ -46,47 +34,17 @@ public class PasswordControllerImpl implements PasswordController { @Override public void validatePassword(String password, ResultHandler resultHandler) { - byte[] encrypted = getEncryptedKey(); - cryptoExecutor.execute(() -> { - byte[] key = crypto.decryptWithPassword(encrypted, password); - if (key == null) { - resultHandler.onResult(false); - } else { - accountManager.setDatabaseKey(new SecretKey(key)); - resultHandler.onResult(true); - } - }); + ioExecutor.execute(() -> + resultHandler.onResult(accountManager.signIn(password))); } @Override - public void changePassword(String password, String newPassword, + public void changePassword(String oldPassword, String newPassword, ResultHandler resultHandler) { - byte[] encrypted = getEncryptedKey(); - cryptoExecutor.execute(() -> { - byte[] key = crypto.decryptWithPassword(encrypted, password); - if (key == null) { - resultHandler.onResult(false); - } else { - String hex = - encryptDatabaseKey(new SecretKey(key), newPassword); - boolean stored = accountManager.storeEncryptedDatabaseKey(hex); - resultHandler.onResult(stored); - } + ioExecutor.execute(() -> { + boolean changed = + accountManager.changePassword(oldPassword, newPassword); + resultHandler.onResult(changed); }); } - - private byte[] getEncryptedKey() { - String hex = accountManager.getEncryptedDatabaseKey(); - if (hex == null) - throw new IllegalStateException("Encrypted database key is null"); - return StringUtils.fromHexString(hex); - } - - @CryptoExecutor - String encryptDatabaseKey(SecretKey key, String password) { - long start = now(); - byte[] encrypted = crypto.encryptWithPassword(key.getBytes(), password); - logDuration(LOG, "Key derivation", start); - return StringUtils.toHexString(encrypted); - } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java index a29d2bc76..2c5109739 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java @@ -3,12 +3,10 @@ package org.briarproject.briar.android.login; import android.support.annotation.Nullable; import org.briarproject.bramble.api.account.AccountManager; -import org.briarproject.bramble.api.crypto.CryptoComponent; -import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; -import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.LocalAuthor; +import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.android.controller.handler.ResultHandler; import org.briarproject.briar.android.controller.handler.UiResultHandler; @@ -32,10 +30,10 @@ public class SetupControllerImpl extends PasswordControllerImpl @Inject SetupControllerImpl(AccountManager accountManager, - @CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto, + @IoExecutor Executor ioExecutor, PasswordStrengthEstimator strengthEstimator, IdentityManager identityManager) { - super(accountManager, cryptoExecutor, crypto, strengthEstimator); + super(accountManager, ioExecutor, strengthEstimator); this.identityManager = identityManager; } @@ -83,10 +81,10 @@ public class SetupControllerImpl extends PasswordControllerImpl @Override public void createAccount() { SetupActivity setupActivity = this.setupActivity; - UiResultHandler resultHandler = - new UiResultHandler(setupActivity) { + UiResultHandler resultHandler = + new UiResultHandler(setupActivity) { @Override - public void onResultUi(Void result) { + public void onResultUi(Boolean result) { if (setupActivity == null) throw new IllegalStateException(); setupActivity.showApp(); @@ -96,23 +94,19 @@ public class SetupControllerImpl extends PasswordControllerImpl } // Package access for testing - void createAccount(ResultHandler resultHandler) { + void createAccount(ResultHandler resultHandler) { SetupActivity setupActivity = this.setupActivity; if (setupActivity == null) throw new IllegalStateException(); String authorName = setupActivity.getAuthorName(); if (authorName == null) throw new IllegalStateException(); String password = setupActivity.getPassword(); if (password == null) throw new IllegalStateException(); - cryptoExecutor.execute(() -> { + ioExecutor.execute(() -> { LOG.info("Creating account"); LocalAuthor localAuthor = identityManager.createLocalAuthor(authorName); identityManager.registerLocalAuthor(localAuthor); - SecretKey key = crypto.generateSecretKey(); - String hex = encryptDatabaseKey(key, password); - accountManager.storeEncryptedDatabaseKey(hex); - accountManager.setDatabaseKey(key); - resultHandler.onResult(null); + resultHandler.onResult(accountManager.createAccount(password)); }); } } diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java index 3c55a199c..aa798f12b 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java @@ -1,7 +1,6 @@ package org.briarproject.briar.android.login; import org.briarproject.bramble.api.account.AccountManager; -import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.ImmediateExecutor; @@ -13,46 +12,28 @@ import java.util.concurrent.atomic.AtomicBoolean; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; -import static org.briarproject.bramble.test.TestUtils.getRandomBytes; -import static org.briarproject.bramble.test.TestUtils.getSecretKey; -import static org.briarproject.bramble.util.StringUtils.toHexString; public class PasswordControllerImplTest extends BrambleMockTestCase { private final AccountManager accountManager = context.mock(AccountManager.class); - private final CryptoComponent crypto = context.mock(CryptoComponent.class); private final PasswordStrengthEstimator estimator = context.mock(PasswordStrengthEstimator.class); - private final Executor cryptoExecutor = new ImmediateExecutor(); + private final Executor ioExecutor = new ImmediateExecutor(); private final String oldPassword = "some.old.pass"; private final String newPassword = "some.new.pass"; - private final byte[] oldEncryptedKey = getRandomBytes(123); - private final byte[] newEncryptedKey = getRandomBytes(123); - private final byte[] key = getSecretKey().getBytes(); - private final String oldEncryptedKeyHex = toHexString(oldEncryptedKey); - private final String newEncryptedKeyHex = toHexString(newEncryptedKey); @Test public void testChangePasswordReturnsTrue() { context.checking(new Expectations() {{ - // Look up the encrypted DB key - oneOf(accountManager).getEncryptedDatabaseKey(); - will(returnValue(oldEncryptedKeyHex)); - // Decrypt and re-encrypt the key - oneOf(crypto).decryptWithPassword(oldEncryptedKey, oldPassword); - will(returnValue(key)); - oneOf(crypto).encryptWithPassword(key, newPassword); - will(returnValue(newEncryptedKey)); - // Store the new key - oneOf(accountManager).storeEncryptedDatabaseKey(newEncryptedKeyHex); + oneOf(accountManager).changePassword(oldPassword, newPassword); will(returnValue(true)); }}); PasswordControllerImpl p = new PasswordControllerImpl(accountManager, - cryptoExecutor, crypto, estimator); + ioExecutor, estimator); AtomicBoolean capturedResult = new AtomicBoolean(false); p.changePassword(oldPassword, newPassword, capturedResult::set); @@ -62,16 +43,12 @@ public class PasswordControllerImplTest extends BrambleMockTestCase { @Test public void testChangePasswordReturnsFalseIfOldPasswordIsWrong() { context.checking(new Expectations() {{ - // Look up the encrypted DB key - oneOf(accountManager).getEncryptedDatabaseKey(); - will(returnValue(oldEncryptedKeyHex)); - // Try to decrypt the key - the password is wrong - oneOf(crypto).decryptWithPassword(oldEncryptedKey, oldPassword); - will(returnValue(null)); + oneOf(accountManager).changePassword(oldPassword, newPassword); + will(returnValue(false)); }}); PasswordControllerImpl p = new PasswordControllerImpl(accountManager, - cryptoExecutor, crypto, estimator); + ioExecutor, estimator); AtomicBoolean capturedResult = new AtomicBoolean(true); p.changePassword(oldPassword, newPassword, capturedResult::set); diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java index 98d342389..5c76733e8 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java @@ -1,9 +1,7 @@ package org.briarproject.briar.android.login; import org.briarproject.bramble.api.account.AccountManager; -import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; -import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.test.BrambleMockTestCase; @@ -18,30 +16,23 @@ import java.util.concurrent.atomic.AtomicBoolean; import static junit.framework.Assert.assertTrue; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.test.TestUtils.getLocalAuthor; -import static org.briarproject.bramble.test.TestUtils.getRandomBytes; -import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.util.StringUtils.getRandomString; -import static org.briarproject.bramble.util.StringUtils.toHexString; public class SetupControllerImplTest extends BrambleMockTestCase { private final AccountManager accountManager = context.mock(AccountManager.class); - private final CryptoComponent crypto = context.mock(CryptoComponent.class); private final PasswordStrengthEstimator estimator = context.mock(PasswordStrengthEstimator.class); private final IdentityManager identityManager = context.mock(IdentityManager.class); private final SetupActivity setupActivity; - private final Executor cryptoExecutor = new ImmediateExecutor(); + private final Executor ioExecutor = new ImmediateExecutor(); private final String authorName = getRandomString(MAX_AUTHOR_NAME_LENGTH); private final String password = "some.strong.pass"; private final LocalAuthor localAuthor = getLocalAuthor(); - private final byte[] encryptedKey = getRandomBytes(123); - private final String encryptedKeyHex = toHexString(encryptedKey); - private final SecretKey key = getSecretKey(); public SetupControllerImplTest() { context.setImposteriser(ClassImposteriser.INSTANCE); @@ -64,21 +55,13 @@ public class SetupControllerImplTest extends BrambleMockTestCase { oneOf(identityManager).createLocalAuthor(authorName); will(returnValue(localAuthor)); oneOf(identityManager).registerLocalAuthor(localAuthor); - // Generate a database key - oneOf(crypto).generateSecretKey(); - will(returnValue(key)); - // Encrypt the key with the password - oneOf(crypto).encryptWithPassword(key.getBytes(), password); - will(returnValue(encryptedKey)); - // Store the encrypted key - oneOf(accountManager).storeEncryptedDatabaseKey(encryptedKeyHex); + // Create the account + oneOf(accountManager).createAccount(password); will(returnValue(true)); - // Pass the database key to the account manager - oneOf(accountManager).setDatabaseKey(key); }}); SetupControllerImpl s = new SetupControllerImpl(accountManager, - cryptoExecutor, crypto, estimator, identityManager); + ioExecutor, estimator, identityManager); s.setSetupActivity(setupActivity); AtomicBoolean called = new AtomicBoolean(false); diff --git a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java index 7aafa6ce4..649add3f2 100644 --- a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java @@ -27,7 +27,6 @@ import org.junit.Test; import java.io.File; import java.util.Collection; -import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -54,7 +53,7 @@ public class FeedManagerIntegrationTest extends BriarTestCase { LocalAuthor localAuthor = identityManager.createLocalAuthor("feedTest"); identityManager.registerLocalAuthor(localAuthor); - component.getAccountManager().setDatabaseKey(getSecretKey()); + component.getAccountManager().createAccount("password"); lifecycleManager = component.getLifecycleManager(); lifecycleManager.startServices(); diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java index c846c1c73..afef68c28 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java @@ -100,11 +100,11 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { private ContactId setUp(SimplexMessagingIntegrationTestComponent device, LocalAuthor local, Author remote, boolean alice) throws Exception { - // Create a database key - device.getAccountManager().setDatabaseKey(getSecretKey()); // Add an identity for the user IdentityManager identityManager = device.getIdentityManager(); identityManager.registerLocalAuthor(local); + // Create an account + device.getAccountManager().createAccount("password"); // Start the lifecycle manager LifecycleManager lifecycleManager = device.getLifecycleManager(); lifecycleManager.startServices(); diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java index 0e30fa848..cfe531782 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java @@ -140,9 +140,9 @@ public abstract class BriarIntegrationTest Date: Fri, 27 Jul 2018 12:06:55 +0100 Subject: [PATCH 10/18] Add javadocs. --- .../account/AndroidAccountManager.java | 23 ++++--- .../bramble/api/account/AccountManager.java | 40 +++++++++++ .../bramble/account/AccountManagerImpl.java | 67 ++++++++++++------- .../briar/android/login/PasswordActivity.java | 1 + 4 files changed, 99 insertions(+), 32 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java index d792672c4..22c279eca 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java @@ -38,12 +38,15 @@ class AndroidAccountManager extends AccountManagerImpl @Override @Nullable protected String loadEncryptedDatabaseKey() { - String key = getDatabaseKeyFromPreferences(); - if (key == null) key = super.loadEncryptedDatabaseKey(); - else migrateDatabaseKeyToFile(key); - return key; + synchronized (stateChangeLock) { + String key = getDatabaseKeyFromPreferences(); + if (key == null) key = super.loadEncryptedDatabaseKey(); + else migrateDatabaseKeyToFile(key); + return key; + } } + // Locking: stateChangeLock @Nullable private String getDatabaseKeyFromPreferences() { String key = prefs.getString(PREF_DB_KEY, null); @@ -52,6 +55,7 @@ class AndroidAccountManager extends AccountManagerImpl return key; } + // Locking: stateChangeLock private void migrateDatabaseKeyToFile(String key) { if (storeEncryptedDatabaseKey(key)) { if (prefs.edit().remove(PREF_DB_KEY).commit()) @@ -64,12 +68,15 @@ class AndroidAccountManager extends AccountManagerImpl @Override public void deleteAccount() { - super.deleteAccount(); - SharedPreferences defaultPrefs = - PreferenceManager.getDefaultSharedPreferences(appContext); - deleteAppData(prefs, defaultPrefs); + synchronized (stateChangeLock) { + super.deleteAccount(); + SharedPreferences defaultPrefs = + PreferenceManager.getDefaultSharedPreferences(appContext); + deleteAppData(prefs, defaultPrefs); + } } + // Locking: stateChangeLock private void deleteAppData(SharedPreferences... clear) { // Clear and commit shared preferences for (SharedPreferences prefs : clear) { diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java index 15d531220..e2784c145 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java @@ -8,18 +8,58 @@ import javax.annotation.Nullable; @NotNullByDefault public interface AccountManager { + /** + * Returns true if the manager has the database key. This will be false + * before {@link #createAccount(String)} or {@link #signIn(String)} has + * been called, and true after {@link #createAccount(String)} or + * {@link #signIn(String)} has returned, until the process exits. + */ boolean hasDatabaseKey(); + /** + * Returns the database key if the manager has it. This will be null + * before {@link #createAccount(String)} or {@link #signIn(String)} has + * been called, and non-null after {@link #createAccount(String)} or + * {@link #signIn(String)} has returned, until the process exits. + */ @Nullable SecretKey getDatabaseKey(); + /** + * Returns true if the encrypted database key can be loaded from disk and + * the database directory exists. + */ boolean accountExists(); + /** + * Creates a database key, encrypts it with the given password and stores + * it on disk. This method does not create the database directory, so + * {@link #accountExists()} will continue to return false until the + * database directory is created. + */ boolean createAccount(String password); + /** + * Deletes all account state from disk. {@link #accountExists()} will + * return false after this method returns. + */ void deleteAccount(); + /** + * Loads the encrypted database key from disk and decrypts it with the + * given password. + * + * @return true if the database key was successfully loaded and decrypted. + */ boolean signIn(String password); + /** + * Loads the encrypted database key from disk, decrypts it with the old + * password, encrypts it with the new password, and stores it on disk, + * replacing the old key. + * + * @return true if the database key was successfully loaded, re-encrypted + * and stored. + */ boolean changePassword(String oldPassword, String newPassword); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java index 4d076fd2e..6162b3e42 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java @@ -38,6 +38,8 @@ class AccountManagerImpl implements AccountManager { private final CryptoComponent crypto; private final File dbKeyFile, dbKeyBackupFile; + protected final Object stateChangeLock = new Object(); + @Nullable private volatile SecretKey databaseKey = null; @@ -63,18 +65,21 @@ class AccountManagerImpl implements AccountManager { @Nullable protected String loadEncryptedDatabaseKey() { - String key = readDbKeyFromFile(dbKeyFile); - if (key == null) { - LOG.info("No database key in primary file"); - key = readDbKeyFromFile(dbKeyBackupFile); - if (key == null) LOG.info("No database key in backup file"); - else LOG.warning("Found database key in backup file"); - } else { - LOG.info("Found database key in primary file"); + synchronized (stateChangeLock) { + String key = readDbKeyFromFile(dbKeyFile); + if (key == null) { + LOG.info("No database key in primary file"); + key = readDbKeyFromFile(dbKeyBackupFile); + if (key == null) LOG.info("No database key in backup file"); + else LOG.warning("Found database key in backup file"); + } else { + LOG.info("Found database key in primary file"); + } + return key; } - return key; } + // Locking: stateChangeLock @Nullable private String readDbKeyFromFile(File f) { if (!f.exists()) { @@ -93,6 +98,7 @@ class AccountManagerImpl implements AccountManager { } } + // Locking: stateChangeLock protected boolean storeEncryptedDatabaseKey(String hex) { LOG.info("Storing database key in file"); // Create the directory if necessary @@ -130,6 +136,7 @@ class AccountManagerImpl implements AccountManager { } } + // Locking: stateChangeLock private void writeDbKeyToFile(String key, File f) throws IOException { FileOutputStream out = new FileOutputStream(f); out.write(key.getBytes("UTF-8")); @@ -139,18 +146,23 @@ class AccountManagerImpl implements AccountManager { @Override public boolean accountExists() { - return loadEncryptedDatabaseKey() != null - && databaseConfig.getDatabaseDirectory().isDirectory(); + synchronized (stateChangeLock) { + return loadEncryptedDatabaseKey() != null + && databaseConfig.getDatabaseDirectory().isDirectory(); + } } @Override public boolean createAccount(String password) { - SecretKey key = crypto.generateSecretKey(); - if (!encryptAndStoreDatabaseKey(key, password)) return false; - databaseKey = key; - return true; + synchronized (stateChangeLock) { + SecretKey key = crypto.generateSecretKey(); + if (!encryptAndStoreDatabaseKey(key, password)) return false; + databaseKey = key; + return true; + } } + // Locking: stateChangeLock private boolean encryptAndStoreDatabaseKey(SecretKey key, String password) { byte[] plaintext = key.getBytes(); byte[] ciphertext = crypto.encryptWithPassword(plaintext, password); @@ -159,19 +171,24 @@ class AccountManagerImpl implements AccountManager { @Override public void deleteAccount() { - LOG.info("Deleting account"); - IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory()); - IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory()); + synchronized (stateChangeLock) { + LOG.info("Deleting account"); + IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory()); + IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory()); + } } @Override public boolean signIn(String password) { - SecretKey key = loadAndDecryptDatabaseKey(password); - if (key == null) return false; - databaseKey = key; - return true; + synchronized (stateChangeLock) { + SecretKey key = loadAndDecryptDatabaseKey(password); + if (key == null) return false; + databaseKey = key; + return true; + } } + // Locking: stateChangeLock @Nullable private SecretKey loadAndDecryptDatabaseKey(String password) { String hex = loadEncryptedDatabaseKey(); @@ -190,7 +207,9 @@ class AccountManagerImpl implements AccountManager { @Override public boolean changePassword(String oldPassword, String newPassword) { - SecretKey key = loadAndDecryptDatabaseKey(oldPassword); - return key != null && encryptAndStoreDatabaseKey(key, newPassword); + synchronized (stateChangeLock) { + SecretKey key = loadAndDecryptDatabaseKey(oldPassword); + return key != null && encryptAndStoreDatabaseKey(key, newPassword); + } } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java index 537d00d08..762744e8a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java @@ -53,6 +53,7 @@ public class PasswordActivity extends BaseActivity { overridePendingTransition(R.anim.fade_in, R.anim.fade_out); if (!accountManager.accountExists()) { + // TODO: Finish instead of deleting account? deleteAccount(); return; } From adbfa263645a404f549f6efc26e1f835a7e6a924 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 27 Jul 2018 14:18:31 +0100 Subject: [PATCH 11/18] Remove redundant locking. --- .../account/AndroidAccountManager.java | 11 ++++----- .../bramble/account/AccountManagerImpl.java | 23 +++++++++---------- .../account/AccountManagerImplTest.java | 6 +++-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java index 22c279eca..e19f2305f 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java @@ -35,15 +35,14 @@ class AndroidAccountManager extends AccountManagerImpl appContext = app.getApplicationContext(); } + // Locking: stateChangeLock @Override @Nullable protected String loadEncryptedDatabaseKey() { - synchronized (stateChangeLock) { - String key = getDatabaseKeyFromPreferences(); - if (key == null) key = super.loadEncryptedDatabaseKey(); - else migrateDatabaseKeyToFile(key); - return key; - } + String key = getDatabaseKeyFromPreferences(); + if (key == null) key = super.loadEncryptedDatabaseKey(); + else migrateDatabaseKeyToFile(key); + return key; } // Locking: stateChangeLock diff --git a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java index 6162b3e42..47ddd87f6 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java @@ -38,7 +38,7 @@ class AccountManagerImpl implements AccountManager { private final CryptoComponent crypto; private final File dbKeyFile, dbKeyBackupFile; - protected final Object stateChangeLock = new Object(); + final Object stateChangeLock = new Object(); @Nullable private volatile SecretKey databaseKey = null; @@ -63,20 +63,19 @@ class AccountManagerImpl implements AccountManager { return databaseKey; } + // Locking: stateChangeLock @Nullable protected String loadEncryptedDatabaseKey() { - synchronized (stateChangeLock) { - String key = readDbKeyFromFile(dbKeyFile); - if (key == null) { - LOG.info("No database key in primary file"); - key = readDbKeyFromFile(dbKeyBackupFile); - if (key == null) LOG.info("No database key in backup file"); - else LOG.warning("Found database key in backup file"); - } else { - LOG.info("Found database key in primary file"); - } - return key; + String key = readDbKeyFromFile(dbKeyFile); + if (key == null) { + LOG.info("No database key in primary file"); + key = readDbKeyFromFile(dbKeyBackupFile); + if (key == null) LOG.info("No database key in backup file"); + else LOG.warning("Found database key in backup file"); + } else { + LOG.info("Found database key in primary file"); } + return key; } // Locking: stateChangeLock diff --git a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java index e0a51898d..6e43e23f8 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java @@ -63,7 +63,8 @@ public class AccountManagerImplTest extends BrambleMockTestCase { assertFalse(keyBackupFile.exists()); assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); - assertEquals(encryptedKeyHex, accountManager.loadEncryptedDatabaseKey()); + assertEquals(encryptedKeyHex, + accountManager.loadEncryptedDatabaseKey()); assertTrue(keyFile.exists()); assertFalse(keyBackupFile.exists()); @@ -81,7 +82,8 @@ public class AccountManagerImplTest extends BrambleMockTestCase { assertTrue(keyBackupFile.exists()); assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); - assertEquals(encryptedKeyHex, accountManager.loadEncryptedDatabaseKey()); + assertEquals(encryptedKeyHex, + accountManager.loadEncryptedDatabaseKey()); assertFalse(keyFile.exists()); assertTrue(keyBackupFile.exists()); From 58d09d0742e8c64a9cd94242ae011ca500010b9d Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 27 Jul 2018 15:29:42 +0100 Subject: [PATCH 12/18] Add tests for AccountManager and AndroidAccountManager. --- .../account/AndroidAccountManager.java | 8 +- .../account/AndroidAccountManagerTest.java | 78 +++++- .../bramble/api/account/AccountManager.java | 8 +- .../account/AccountManagerImplTest.java | 245 +++++++++++++++--- 4 files changed, 298 insertions(+), 41 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java index e19f2305f..1ce36ed39 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java @@ -69,12 +69,16 @@ class AndroidAccountManager extends AccountManagerImpl public void deleteAccount() { synchronized (stateChangeLock) { super.deleteAccount(); - SharedPreferences defaultPrefs = - PreferenceManager.getDefaultSharedPreferences(appContext); + SharedPreferences defaultPrefs = getDefaultSharedPreferences(); deleteAppData(prefs, defaultPrefs); } } + // Package access for testing + SharedPreferences getDefaultSharedPreferences() { + return PreferenceManager.getDefaultSharedPreferences(appContext); + } + // Locking: stateChangeLock private void deleteAppData(SharedPreferences... clear) { // Clear and commit shared preferences diff --git a/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java b/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java index 1922954a0..d283adcea 100644 --- a/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java +++ b/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.account; import android.app.Application; import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.db.DatabaseConfig; @@ -25,37 +26,50 @@ import static org.briarproject.bramble.util.StringUtils.toHexString; public class AndroidAccountManagerTest extends BrambleMockTestCase { private final SharedPreferences prefs = - context.mock(SharedPreferences.class); + context.mock(SharedPreferences.class, "prefs"); + private final SharedPreferences defaultPrefs = + context.mock(SharedPreferences.class, "defaultPrefs"); private final DatabaseConfig databaseConfig = context.mock(DatabaseConfig.class); private final CryptoComponent crypto = context.mock(CryptoComponent.class); private final SharedPreferences.Editor editor = context.mock(SharedPreferences.Editor.class); private final Application app; + private final ApplicationInfo applicationInfo; private final String encryptedKeyHex = toHexString(getRandomBytes(123)); private final File testDir = getTestDirectory(); private final File keyDir = new File(testDir, "key"); private final File keyFile = new File(keyDir, "db.key"); private final File keyBackupFile = new File(keyDir, "db.key.bak"); + private final File dbDir = new File(testDir, "db"); private AndroidAccountManager accountManager; public AndroidAccountManagerTest() { context.setImposteriser(ClassImposteriser.INSTANCE); app = context.mock(Application.class); + applicationInfo = new ApplicationInfo(); + applicationInfo.dataDir = testDir.getAbsolutePath(); } @Before public void setUp() { context.checking(new Expectations() {{ + allowing(databaseConfig).getDatabaseDirectory(); + will(returnValue(dbDir)); allowing(databaseConfig).getDatabaseKeyDirectory(); will(returnValue(keyDir)); allowing(app).getApplicationContext(); will(returnValue(app)); }}); accountManager = new AndroidAccountManager(databaseConfig, crypto, - prefs, app); + prefs, app) { + @Override + SharedPreferences getDefaultSharedPreferences() { + return defaultPrefs; + } + }; } @Test @@ -74,12 +88,70 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase { assertFalse(keyFile.exists()); assertFalse(keyBackupFile.exists()); - assertEquals(encryptedKeyHex, accountManager.loadEncryptedDatabaseKey()); + assertEquals(encryptedKeyHex, + accountManager.loadEncryptedDatabaseKey()); assertTrue(keyFile.exists()); assertTrue(keyBackupFile.exists()); } + @Test + public void testDeleteAccountClearsSharedPrefsAndDeletesFiles() + throws Exception { + // Directories 'lib' and 'shared_prefs' should be spared + File libDir = new File(testDir, "lib"); + File libFile = new File(libDir, "file"); + File sharedPrefsDir = new File(testDir, "shared_prefs"); + File sharedPrefsFile = new File(sharedPrefsDir, "file"); + // Directory 'cache' should be emptied + File cacheDir = new File(testDir, "cache"); + File cacheFile = new File(cacheDir, "file"); + // Other directories should be deleted + File potatoDir = new File(testDir, ".potato"); + File potatoFile = new File(potatoDir, "file"); + + context.checking(new Expectations() {{ + oneOf(prefs).edit(); + will(returnValue(editor)); + oneOf(editor).clear(); + will(returnValue(editor)); + oneOf(editor).commit(); + will(returnValue(true)); + oneOf(defaultPrefs).edit(); + will(returnValue(editor)); + oneOf(editor).clear(); + will(returnValue(editor)); + oneOf(editor).commit(); + will(returnValue(true)); + oneOf(app).getApplicationInfo(); + will(returnValue(applicationInfo)); + }}); + + assertTrue(dbDir.mkdirs()); + assertTrue(keyDir.mkdirs()); + assertTrue(libDir.mkdirs()); + assertTrue(libFile.createNewFile()); + assertTrue(sharedPrefsDir.mkdirs()); + assertTrue(sharedPrefsFile.createNewFile()); + assertTrue(cacheDir.mkdirs()); + assertTrue(cacheFile.createNewFile()); + assertTrue(potatoDir.mkdirs()); + assertTrue(potatoFile.createNewFile()); + + accountManager.deleteAccount(); + + assertFalse(dbDir.exists()); + assertFalse(keyDir.exists()); + assertTrue(libDir.exists()); + assertTrue(libFile.exists()); + assertTrue(sharedPrefsDir.exists()); + assertTrue(sharedPrefsFile.exists()); + assertTrue(cacheDir.exists()); + assertFalse(cacheFile.exists()); + assertFalse(potatoDir.exists()); + assertFalse(potatoFile.exists()); + } + @After public void tearDown() { deleteTestDirectory(testDir); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java index e2784c145..5b475ae63 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java @@ -12,7 +12,7 @@ public interface AccountManager { * Returns true if the manager has the database key. This will be false * before {@link #createAccount(String)} or {@link #signIn(String)} has * been called, and true after {@link #createAccount(String)} or - * {@link #signIn(String)} has returned, until the process exits. + * {@link #signIn(String)} has returned true, until the process exits. */ boolean hasDatabaseKey(); @@ -20,14 +20,14 @@ public interface AccountManager { * Returns the database key if the manager has it. This will be null * before {@link #createAccount(String)} or {@link #signIn(String)} has * been called, and non-null after {@link #createAccount(String)} or - * {@link #signIn(String)} has returned, until the process exits. + * {@link #signIn(String)} has returned true, until the process exits. */ @Nullable SecretKey getDatabaseKey(); /** - * Returns true if the encrypted database key can be loaded from disk and - * the database directory exists. + * Returns true if the encrypted database key can be loaded from disk, and + * the database directory exists and is a directory. */ boolean accountExists(); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java index 6e43e23f8..998fa1c5e 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java @@ -1,6 +1,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.test.BrambleMockTestCase; import org.jmock.Expectations; @@ -22,9 +23,12 @@ 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.getRandomBytes; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getTestDirectory; import static org.briarproject.bramble.util.StringUtils.toHexString; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; public class AccountManagerImplTest extends BrambleMockTestCase { @@ -32,10 +36,15 @@ public class AccountManagerImplTest extends BrambleMockTestCase { context.mock(DatabaseConfig.class); private final CryptoComponent crypto = context.mock(CryptoComponent.class); + private final SecretKey key = getSecretKey(); private final byte[] encryptedKey = getRandomBytes(123); private final String encryptedKeyHex = toHexString(encryptedKey); - private final String oldEncryptedKeyHex = toHexString(getRandomBytes(123)); + private final byte[] newEncryptedKey = getRandomBytes(123); + private final String newEncryptedKeyHex = toHexString(newEncryptedKey); + private final String password = "some.password"; + private final String newPassword = "some.new.password"; private final File testDir = getTestDirectory(); + private final File dbDir = new File(testDir, "db"); private final File keyDir = new File(testDir, "key"); private final File keyFile = new File(keyDir, "db.key"); private final File keyBackupFile = new File(keyDir, "db.key.bak"); @@ -45,56 +54,115 @@ public class AccountManagerImplTest extends BrambleMockTestCase { @Before public void setUp() { context.checking(new Expectations() {{ + allowing(databaseConfig).getDatabaseDirectory(); + will(returnValue(dbDir)); allowing(databaseConfig).getDatabaseKeyDirectory(); will(returnValue(keyDir)); }}); - assertTrue(keyDir.mkdirs()); + accountManager = new AccountManagerImpl(databaseConfig, crypto); + + assertFalse(keyFile.exists()); + assertFalse(keyBackupFile.exists()); + } + + @Test + public void testCreatingAccountStoresDbKey() throws Exception { + context.checking(new Expectations() {{ + oneOf(crypto).generateSecretKey(); + will(returnValue(key)); + oneOf(crypto).encryptWithPassword(key.getBytes(), password); + will(returnValue(encryptedKey)); + }}); + + accountManager.createAccount(password); + + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); + } + + @Test + public void testSignInReturnsFalseIfDbKeyCannotBeLoaded() { + assertFalse(accountManager.signIn(password)); + assertFalse(accountManager.hasDatabaseKey()); + + assertFalse(keyFile.exists()); + assertFalse(keyBackupFile.exists()); + } + + @Test + public void testSignInReturnsFalseIfPasswordIsWrong() throws Exception { + context.checking(new Expectations() {{ + oneOf(crypto).decryptWithPassword(encryptedKey, password); + will(returnValue(null)); + }}); + + storeDatabaseKey(keyFile, encryptedKeyHex); + storeDatabaseKey(keyBackupFile, encryptedKeyHex); + + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); + + assertFalse(accountManager.signIn(password)); + assertFalse(accountManager.hasDatabaseKey()); + + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); + } + + @Test + public void testSignInReturnsTrueIfPasswordIsRight() throws Exception { + context.checking(new Expectations() {{ + oneOf(crypto).decryptWithPassword(encryptedKey, password); + will(returnValue(key.getBytes())); + }}); + + storeDatabaseKey(keyFile, encryptedKeyHex); + storeDatabaseKey(keyBackupFile, encryptedKeyHex); + + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); + + assertTrue(accountManager.signIn(password)); + assertTrue(accountManager.hasDatabaseKey()); + SecretKey decrypted = accountManager.getDatabaseKey(); + assertNotNull(decrypted); + assertArrayEquals(key.getBytes(), decrypted.getBytes()); + + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); } @Test public void testDbKeyIsLoadedFromPrimaryFile() throws Exception { - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - storeDatabaseKey(keyFile, encryptedKeyHex); - assertTrue(keyFile.exists()); - assertFalse(keyBackupFile.exists()); assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertFalse(keyBackupFile.exists()); assertEquals(encryptedKeyHex, accountManager.loadEncryptedDatabaseKey()); - assertTrue(keyFile.exists()); - assertFalse(keyBackupFile.exists()); assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertFalse(keyBackupFile.exists()); } @Test public void testDbKeyIsLoadedFromBackupFile() throws Exception { - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - storeDatabaseKey(keyBackupFile, encryptedKeyHex); assertFalse(keyFile.exists()); - assertTrue(keyBackupFile.exists()); assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); assertEquals(encryptedKeyHex, accountManager.loadEncryptedDatabaseKey()); assertFalse(keyFile.exists()); - assertTrue(keyBackupFile.exists()); assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); } @Test public void testDbKeyIsNullIfNotFound() { - assertFalse(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - assertNull(accountManager.loadEncryptedDatabaseKey()); assertFalse(keyFile.exists()); @@ -103,43 +171,156 @@ public class AccountManagerImplTest extends BrambleMockTestCase { @Test public void testStoringDbKeyOverwritesPrimary() throws Exception { + storeDatabaseKey(keyFile, encryptedKeyHex); + + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertFalse(keyBackupFile.exists()); + + assertTrue(accountManager.storeEncryptedDatabaseKey( + newEncryptedKeyHex)); + + assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile)); + } + + @Test + public void testStoringDbKeyOverwritesBackup() throws Exception { + storeDatabaseKey(keyBackupFile, encryptedKeyHex); + + assertFalse(keyFile.exists()); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); + + assertTrue(accountManager.storeEncryptedDatabaseKey( + newEncryptedKeyHex)); + + assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile)); + } + + @Test + public void testAccountExistsReturnsFalseIfDbKeyCannotBeLoaded() { + assertFalse(accountManager.accountExists()); + assertFalse(keyFile.exists()); assertFalse(keyBackupFile.exists()); + } - storeDatabaseKey(keyFile, oldEncryptedKeyHex); + @Test + public void testAccountExistsReturnsFalseIfDbDirectoryDoesNotExist() + throws Exception { + storeDatabaseKey(keyFile, encryptedKeyHex); + storeDatabaseKey(keyBackupFile, encryptedKeyHex); - assertTrue(keyFile.exists()); - assertFalse(keyBackupFile.exists()); - assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyFile)); + assertFalse(dbDir.exists()); - assertTrue(accountManager.storeEncryptedDatabaseKey(encryptedKeyHex)); + assertFalse(accountManager.accountExists()); + + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); + assertFalse(dbDir.exists()); + } + + @Test + public void testAccountExistsReturnsFalseIfDbDirectoryIsNotDirectory() + throws Exception { + storeDatabaseKey(keyFile, encryptedKeyHex); + storeDatabaseKey(keyBackupFile, encryptedKeyHex); + + assertTrue(dbDir.createNewFile()); + assertFalse(dbDir.isDirectory()); + + assertFalse(accountManager.accountExists()); + + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); + assertTrue(dbDir.exists()); + assertFalse(dbDir.isDirectory()); + } + + @Test + public void testAccountExistsReturnsTrueIfDbDirectoryIsDirectory() + throws Exception { + storeDatabaseKey(keyFile, encryptedKeyHex); + storeDatabaseKey(keyBackupFile, encryptedKeyHex); + + assertTrue(dbDir.mkdirs()); + assertTrue(dbDir.isDirectory()); + + assertTrue(accountManager.accountExists()); + + assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); + assertTrue(dbDir.exists()); + assertTrue(dbDir.isDirectory()); + } + + @Test + public void testCreateAccountStoresDbKey() throws Exception { + context.checking(new Expectations() {{ + oneOf(crypto).generateSecretKey(); + will(returnValue(key)); + oneOf(crypto).encryptWithPassword(key.getBytes(), password); + will(returnValue(encryptedKey)); + }}); + + assertFalse(accountManager.hasDatabaseKey()); + + assertTrue(accountManager.createAccount(password)); + + assertTrue(accountManager.hasDatabaseKey()); + SecretKey dbKey = accountManager.getDatabaseKey(); + assertNotNull(dbKey); + assertArrayEquals(key.getBytes(), dbKey.getBytes()); - assertTrue(keyFile.exists()); - assertTrue(keyBackupFile.exists()); assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); } @Test - public void testStoringDbKeyOverwritesBackup() throws Exception { + public void testChangePasswordReturnsFalseIfDbKeyCannotBeLoaded() { + assertFalse(accountManager.changePassword(password, newPassword)); + assertFalse(keyFile.exists()); assertFalse(keyBackupFile.exists()); + } - storeDatabaseKey(keyBackupFile, oldEncryptedKeyHex); + @Test + public void testChangePasswordReturnsFalseIfPasswordIsWrong() + throws Exception { + context.checking(new Expectations() {{ + oneOf(crypto).decryptWithPassword(encryptedKey, password); + will(returnValue(null)); + }}); - assertFalse(keyFile.exists()); - assertTrue(keyBackupFile.exists()); - assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyBackupFile)); + storeDatabaseKey(keyFile, encryptedKeyHex); + storeDatabaseKey(keyBackupFile, encryptedKeyHex); - assertTrue(accountManager.storeEncryptedDatabaseKey(encryptedKeyHex)); + assertFalse(accountManager.changePassword(password, newPassword)); - assertTrue(keyFile.exists()); - assertTrue(keyBackupFile.exists()); assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); } + @Test + public void testChangePasswordReturnsTrueIfPasswordIsRight() throws Exception { + context.checking(new Expectations() {{ + oneOf(crypto).decryptWithPassword(encryptedKey, password); + will(returnValue(key.getBytes())); + oneOf(crypto).encryptWithPassword(key.getBytes(), newPassword); + will(returnValue(newEncryptedKey)); + }}); + + storeDatabaseKey(keyFile, encryptedKeyHex); + storeDatabaseKey(keyBackupFile, encryptedKeyHex); + + assertTrue(accountManager.changePassword(password, newPassword)); + + assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile)); + assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile)); + } + private void storeDatabaseKey(File f, String hex) throws IOException { + f.getParentFile().mkdirs(); FileOutputStream out = new FileOutputStream(f); out.write(hex.getBytes("UTF-8")); out.flush(); From 287f3760cdf094f4cc2ae24fdb99004a90f09dfa Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 27 Jul 2018 15:38:48 +0100 Subject: [PATCH 13/18] Pass database key into LifecycleManager. --- .../bramble/api/contact/ContactManager.java | 2 +- .../bramble/api/lifecycle/LifecycleManager.java | 15 ++++++++------- .../bramble/api/sync/ValidationManager.java | 7 +++++-- .../api/versioning/ClientVersioningManager.java | 3 ++- .../bramble/lifecycle/LifecycleManagerImpl.java | 11 +++-------- .../bramble/test/TestLifecycleModule.java | 3 ++- .../briarproject/briar/android/BriarService.java | 6 ++++-- .../briar/feed/FeedManagerIntegrationTest.java | 5 ++--- .../feed/FeedManagerIntegrationTestComponent.java | 5 ----- .../IntroductionIntegrationTestComponent.java | 2 -- .../SimplexMessagingIntegrationTest.java | 4 +--- .../SimplexMessagingIntegrationTestComponent.java | 5 ----- .../briar/test/BriarIntegrationTest.java | 9 +++------ .../briar/test/BriarIntegrationTestComponent.java | 5 ----- 14 files changed, 31 insertions(+), 51 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java index 589fa53c2..517dcb89f 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java @@ -16,7 +16,7 @@ public interface ContactManager { /** * Registers a hook to be called whenever a contact is added or removed. * This method should be called before - * {@link LifecycleManager#startServices()}. + * {@link LifecycleManager#startServices(SecretKey)}. */ void registerContactHook(ContactHook hook); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java index c54910b62..c44cf8879 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/lifecycle/LifecycleManager.java @@ -1,5 +1,6 @@ package org.briarproject.bramble.api.lifecycle; +import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.Client; @@ -16,7 +17,7 @@ import java.util.concurrent.ExecutorService; public interface LifecycleManager { /** - * The result of calling {@link #startServices()}. + * The result of calling {@link #startServices(SecretKey)}. */ enum StartResult { ALREADY_RUNNING, @@ -42,27 +43,27 @@ public interface LifecycleManager { /** * Registers a {@link Service} to be started and stopped. This method - * should be called before {@link #startServices()}. + * should be called before {@link #startServices(SecretKey)}. */ void registerService(Service s); /** * Registers a {@link Client} to be started. This method should be called - * before {@link #startServices()}. + * before {@link #startServices(SecretKey)}. */ void registerClient(Client c); /** * Registers an {@link ExecutorService} to be shut down. This method - * should be called before {@link #startServices()}. + * should be called before {@link #startServices(SecretKey)}. */ void registerForShutdown(ExecutorService e); /** - * Opens the {@link DatabaseComponent} and starts any registered - * {@link Client Clients} and {@link Service Services}. + * Opens the {@link DatabaseComponent} using the given key and starts any + * registered {@link Client Clients} and {@link Service Services}. */ - StartResult startServices(); + StartResult startServices(SecretKey dbKey); /** * Stops any registered {@link Service Services}, shuts down any diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/ValidationManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/ValidationManager.java index 5fe103ce8..3b5c90342 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/ValidationManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/ValidationManager.java @@ -1,5 +1,6 @@ package org.briarproject.bramble.api.sync; +import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Metadata; import org.briarproject.bramble.api.db.Transaction; @@ -35,7 +36,8 @@ public interface ValidationManager { /** * Registers the message validator for the given client. This method - * should be called before {@link LifecycleManager#startServices()}. + * should be called before + * {@link LifecycleManager#startServices(SecretKey)}. */ void registerMessageValidator(ClientId c, int majorVersion, MessageValidator v); @@ -43,7 +45,8 @@ public interface ValidationManager { /** * Registers the incoming message hook for the given client. The hook will * be called once for each incoming message that passes validation. This - * method should be called before {@link LifecycleManager#startServices()}. + * method should be called before + * {@link LifecycleManager#startServices(SecretKey)}. */ void registerIncomingMessageHook(ClientId c, int majorVersion, IncomingMessageHook hook); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/versioning/ClientVersioningManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/versioning/ClientVersioningManager.java index f2e98ea2c..00b3d672c 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/versioning/ClientVersioningManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/versioning/ClientVersioningManager.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.api.versioning; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.lifecycle.LifecycleManager; @@ -25,7 +26,7 @@ public interface ClientVersioningManager { /** * Registers a client that will be advertised to contacts. The hook will * be called when the visibility of the client changes. This method should - * be called before {@link LifecycleManager#startServices()}. + * be called before {@link LifecycleManager#startServices(SecretKey)}. */ void registerClient(ClientId clientId, int majorVersion, int minorVersion, ClientVersioningHook hook); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java index a2c4d7e3f..130595ab6 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleManagerImpl.java @@ -1,6 +1,5 @@ package org.briarproject.bramble.lifecycle; -import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DataTooNewException; import org.briarproject.bramble.api.db.DataTooOldException; @@ -57,7 +56,6 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener { private final List services; private final List clients; private final List executors; - private final AccountManager accountManager; private final IdentityManager identityManager; private final Semaphore startStopSemaphore = new Semaphore(1); private final CountDownLatch dbLatch = new CountDownLatch(1); @@ -68,10 +66,9 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener { @Inject LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus, - AccountManager accountManager, IdentityManager identityManager) { + IdentityManager identityManager) { this.db = db; this.eventBus = eventBus; - this.accountManager = accountManager; this.identityManager = identityManager; services = new CopyOnWriteArrayList<>(); clients = new CopyOnWriteArrayList<>(); @@ -99,7 +96,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener { } @Override - public StartResult startServices() { + public StartResult startServices(SecretKey dbKey) { if (!startStopSemaphore.tryAcquire()) { LOG.info("Already starting or stopping"); return ALREADY_RUNNING; @@ -108,9 +105,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener { LOG.info("Starting services"); long start = now(); - SecretKey key = accountManager.getDatabaseKey(); - if (key == null) throw new IllegalStateException(); - boolean reopened = db.open(key, this); + boolean reopened = db.open(dbKey, this); if (reopened) logDuration(LOG, "Reopening database", start); else logDuration(LOG, "Creating database", start); identityManager.storeLocalAuthor(); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/test/TestLifecycleModule.java b/bramble-core/src/test/java/org/briarproject/bramble/test/TestLifecycleModule.java index 01d97c52b..21f6ccfe9 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/test/TestLifecycleModule.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/test/TestLifecycleModule.java @@ -1,5 +1,6 @@ package org.briarproject.bramble.test; +import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.Service; @@ -39,7 +40,7 @@ public class TestLifecycleModule { } @Override - public StartResult startServices() { + public StartResult startServices(SecretKey dbKey) { return StartResult.SUCCESS; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java index 980e6cdfc..9e43ca2b2 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java @@ -18,6 +18,7 @@ import android.support.v4.app.NotificationCompat; import android.support.v4.content.ContextCompat; import org.briarproject.bramble.api.account.AccountManager; +import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult; import org.briarproject.bramble.api.system.AndroidExecutor; @@ -97,7 +98,8 @@ public class BriarService extends Service { stopSelf(); return; } - if (!accountManager.hasDatabaseKey()) { + SecretKey dbKey = accountManager.getDatabaseKey(); + if (dbKey == null) { LOG.info("No database key"); stopSelf(); return; @@ -142,7 +144,7 @@ public class BriarService extends Service { nm.cancel(REMINDER_NOTIFICATION_ID); // Start the services in a background thread new Thread(() -> { - StartResult result = lifecycleManager.startServices(); + StartResult result = lifecycleManager.startServices(dbKey); if (result == SUCCESS) { started = true; } else if (result == ALREADY_RUNNING) { diff --git a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java index 649add3f2..ced26a4a1 100644 --- a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTest.java @@ -27,6 +27,7 @@ import org.junit.Test; import java.io.File; import java.util.Collection; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -53,10 +54,8 @@ public class FeedManagerIntegrationTest extends BriarTestCase { LocalAuthor localAuthor = identityManager.createLocalAuthor("feedTest"); identityManager.registerLocalAuthor(localAuthor); - component.getAccountManager().createAccount("password"); - lifecycleManager = component.getLifecycleManager(); - lifecycleManager.startServices(); + lifecycleManager.startServices(getSecretKey()); lifecycleManager.waitForStartup(); feedManager = component.getFeedManager(); diff --git a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java index 3fc4a9ea6..685eedacb 100644 --- a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerIntegrationTestComponent.java @@ -1,7 +1,5 @@ package org.briarproject.briar.feed; -import org.briarproject.bramble.account.AccountModule; -import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.client.ClientModule; @@ -38,7 +36,6 @@ import dagger.Component; TestSecureRandomModule.class, TestSocksModule.class, TestDnsModule.class, - AccountModule.class, BriarClientModule.class, ClientModule.class, ContactModule.class, @@ -82,8 +79,6 @@ interface FeedManagerIntegrationTestComponent { IdentityManager getIdentityManager(); - AccountManager getAccountManager(); - LifecycleManager getLifecycleManager(); FeedManager getFeedManager(); diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java index 2da286b05..108f48849 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java @@ -1,6 +1,5 @@ package org.briarproject.briar.introduction; -import org.briarproject.bramble.account.AccountModule; import org.briarproject.bramble.client.ClientModule; import org.briarproject.bramble.contact.ContactModule; import org.briarproject.bramble.crypto.CryptoExecutorModule; @@ -37,7 +36,6 @@ import dagger.Component; TestDatabaseModule.class, TestPluginConfigModule.class, TestSecureRandomModule.class, - AccountModule.class, BlogModule.class, BriarClientModule.class, ClientModule.class, diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java index afef68c28..c17f3a35d 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java @@ -103,11 +103,9 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { // Add an identity for the user IdentityManager identityManager = device.getIdentityManager(); identityManager.registerLocalAuthor(local); - // Create an account - device.getAccountManager().createAccount("password"); // Start the lifecycle manager LifecycleManager lifecycleManager = device.getLifecycleManager(); - lifecycleManager.startServices(); + lifecycleManager.startServices(getSecretKey()); lifecycleManager.waitForStartup(); // Add the other user as a contact ContactManager contactManager = device.getContactManager(); diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java index a5f9d9bc6..7dade1ed1 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java @@ -1,7 +1,5 @@ package org.briarproject.briar.messaging; -import org.briarproject.bramble.account.AccountModule; -import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.identity.IdentityManager; @@ -41,7 +39,6 @@ import dagger.Component; TestDatabaseModule.class, TestPluginConfigModule.class, TestSecureRandomModule.class, - AccountModule.class, BriarClientModule.class, ClientModule.class, ContactModule.class, @@ -80,8 +77,6 @@ interface SimplexMessagingIntegrationTestComponent { IdentityManager getIdentityManager(); - AccountManager getAccountManager(); - ContactManager getContactManager(); MessagingManager getMessagingManager(); diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java index cfe531782..f10d94183 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java @@ -140,9 +140,6 @@ public abstract class BriarIntegrationTest Date: Fri, 27 Jul 2018 16:04:57 +0100 Subject: [PATCH 14/18] Add hashes for test dependencies. --- bramble-android/build.gradle | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/bramble-android/build.gradle b/bramble-android/build.gradle index a07147eb2..4b322b362 100644 --- a/bramble-android/build.gradle +++ b/bramble-android/build.gradle @@ -51,6 +51,10 @@ dependencies { dependencyVerification { verify = [ + 'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861', + 'com.android.support.test:monitor:1.0.2:monitor-1.0.2.aar:38ef4fa98a32dc55550ff49bb36a583e178b3a9b830fcb8dcc27bfc4254bc2bc', + 'com.android.support.test:runner:1.0.2:runner-1.0.2.aar:f04b9ae342975ba1cb3e4a06e13426e3e6b8a73faa45acba604493d83c9a4f00', + 'com.android.support:support-annotations:27.1.1:support-annotations-27.1.1.jar:3365960206c3d2b09e845f555e7f88f8effc8d2f00b369e66c4be384029299cf', 'com.android.tools.analytics-library:protos:26.1.3:protos-26.1.3.jar:818c9f256f141d9dafec03a1aa2b94d240b2c140acfd7ee31a8b3e6c2b9479e3', 'com.android.tools.analytics-library:shared:26.1.3:shared-26.1.3.jar:7110706c7ada96c8b6f5ca80c478291bc7899d46277de2c48527e045442401a3', 'com.android.tools.analytics-library:tracker:26.1.3:tracker-26.1.3.jar:4155424bf2ce4872da83332579a1707252bc66cbd77c5144fdc4483d0f2e1418', @@ -99,12 +103,16 @@ dependencyVerification { 'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f', 'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2', + 'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a', 'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5', 'net.sf.kxml:kxml2:2.3.0:kxml2-2.3.0.jar:f264dd9f79a1fde10ce5ecc53221eff24be4c9331c830b7d52f2f08a7b633de2', + 'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d', + 'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8', 'org.apache.commons:commons-compress:1.12:commons-compress-1.12.jar:2c1542faf343185b7cab9c3d55c8ae5471d6d095d3887a4adefdbdf2984dc0b6', 'org.apache.httpcomponents:httpclient:4.2.6:httpclient-4.2.6.jar:362e9324ee7c697e21279e20077b52737ddef3f1b2c1a7abe5ad34b465145550', 'org.apache.httpcomponents:httpcore:4.2.5:httpcore-4.2.5.jar:e5e82da4cc66c8d917bbf743e3c0752efe8522735e7fc9dbddb65bccea81cfe9', 'org.apache.httpcomponents:httpmime:4.1:httpmime-4.1.jar:31629566148e8a47688ae43b420abc3ecd783ed15b33bebc00824bf24c9b15aa', + 'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8', 'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca', 'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349', 'org.briarproject:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864', @@ -114,17 +122,25 @@ dependencyVerification { 'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa', 'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70', 'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea', + 'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9', + 'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c', 'org.jetbrains.kotlin:kotlin-reflect:1.2.0:kotlin-reflect-1.2.0.jar:4f48a872bad6e4d9c053f4ad610d11e4012ad7e58dc19a03dd5eb811f36069dd', 'org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.0:kotlin-stdlib-jre7-1.2.0.jar:c7a20fb951d437797afe8980aff6c1e5a03f310c661ba58ba1d4fa90cb0f2926', 'org.jetbrains.kotlin:kotlin-stdlib-jre8:1.2.0:kotlin-stdlib-jre8-1.2.0.jar:633524eee6ef1941f7cb1dab7ee3927b0a221ceee9047aeb5515f4cbb990c82a', 'org.jetbrains.kotlin:kotlin-stdlib:1.2.0:kotlin-stdlib-1.2.0.jar:05cfd9f5ac0b41910703a8925f7211a495909b27a2ffdd1c5106f1689aeafcd4', 'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7', 'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478', + 'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c', + 'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b', + 'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760', + 'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16', 'org.jvnet.staxex:stax-ex:1.7.7:stax-ex-1.7.7.jar:a31ff7d77163c0deb09e7fee59ad35ae44c2cee2cc8552a116ccd1583d813fb4', + 'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80', 'org.ow2.asm:asm-analysis:5.1:asm-analysis-5.1.jar:a34658f5c5de4b573eef21131cc32cc25f7b66407944f312b28ec2e56abb1fa9', 'org.ow2.asm:asm-commons:5.1:asm-commons-5.1.jar:97b3786e1f55e74bddf8ad102bf50e33bbcbc1f6b7fd7b36f0bbbb25cd4981be', 'org.ow2.asm:asm-tree:5.1:asm-tree-5.1.jar:c0de2bbc4cb8297419659813ecd4ed1d077ed1dd5c1f5544cc5143e493e84c10', 'org.ow2.asm:asm-util:5.1:asm-util-5.1.jar:ee032c39ae5e3cd099148fbba9a2124f9ed613e5cb93e03ee0fa8808ce364040', + 'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220', 'org.ow2.asm:asm:5.1:asm-5.1.jar:d2da399a9967c69f0a21739256fa79d284222c223082cacadc17372244764b54', ] } From f8df6b88eef474e3edee218c511c0461303e475f Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 1 Aug 2018 12:19:05 +0100 Subject: [PATCH 15/18] Add BriarAccountManager subclass. --- .../bramble/BrambleAndroidModule.java | 2 -- .../account/AndroidAccountManager.java | 2 +- .../bramble/account/BriarAccountManager.java | 31 +++++++++++++++++++ .../bramble/account/BriarAccountModule.java | 4 +-- .../briar/android/AndroidComponent.java | 12 ++----- .../briar/android/login/PasswordActivity.java | 3 -- 6 files changed, 36 insertions(+), 18 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java rename bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountModule.java => briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountModule.java (68%) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java b/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java index d2e2979b6..cb563508a 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java @@ -2,7 +2,6 @@ package org.briarproject.bramble; import android.app.Application; -import org.briarproject.bramble.account.AndroidAccountModule; import org.briarproject.bramble.plugin.tor.CircumventionProvider; import org.briarproject.bramble.plugin.tor.CircumventionProviderImpl; import org.briarproject.bramble.system.AndroidSystemModule; @@ -13,7 +12,6 @@ import dagger.Module; import dagger.Provides; @Module(includes = { - AndroidAccountModule.class, AndroidSystemModule.class }) public class BrambleAndroidModule { diff --git a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java index 1ce36ed39..9636c3dc0 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java @@ -24,8 +24,8 @@ class AndroidAccountManager extends AccountManagerImpl private static final String PREF_DB_KEY = "key"; + protected final Context appContext; private final SharedPreferences prefs; - private final Context appContext; @Inject AndroidAccountManager(DatabaseConfig databaseConfig, diff --git a/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java b/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java new file mode 100644 index 000000000..e1fee81cd --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java @@ -0,0 +1,31 @@ +package org.briarproject.bramble.account; + +import android.app.Application; +import android.content.SharedPreferences; + +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.briar.R; +import org.briarproject.briar.android.Localizer; +import org.briarproject.briar.android.util.UiUtils; + +import javax.inject.Inject; + +class BriarAccountManager extends AndroidAccountManager { + + @Inject + BriarAccountManager(DatabaseConfig databaseConfig, CryptoComponent crypto, + SharedPreferences prefs, Application app) { + super(databaseConfig, crypto, prefs, app); + } + + @Override + public void deleteAccount() { + synchronized (stateChangeLock) { + super.deleteAccount(); + Localizer.reinitialize(); + UiUtils.setTheme(appContext, + appContext.getString(R.string.pref_theme_light_value)); + } + } +} diff --git a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountModule.java b/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountModule.java similarity index 68% rename from bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountModule.java rename to briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountModule.java index 4e74ef9ea..3ed782d77 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountModule.java +++ b/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountModule.java @@ -8,11 +8,11 @@ import dagger.Module; import dagger.Provides; @Module -public class AndroidAccountModule { +public class BriarAccountModule { @Provides @Singleton - AccountManager provideAccountManager(AndroidAccountManager accountManager) { + AccountManager provideAccountManager(BriarAccountManager accountManager) { return accountManager; } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java index 8935cfb7f..75b25b099 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java @@ -1,17 +1,14 @@ package org.briarproject.briar.android; -import android.content.SharedPreferences; - import org.briarproject.bramble.BrambleAndroidModule; import org.briarproject.bramble.BrambleCoreEagerSingletons; import org.briarproject.bramble.BrambleCoreModule; +import org.briarproject.bramble.account.BriarAccountModule; import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.contact.ContactExchangeTask; import org.briarproject.bramble.api.contact.ContactManager; -import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; -import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.identity.IdentityManager; @@ -63,6 +60,7 @@ import dagger.Component; BrambleCoreModule.class, BriarCoreModule.class, BrambleAndroidModule.class, + BriarAccountModule.class, AppModule.class }) public interface AndroidComponent @@ -74,10 +72,6 @@ public interface AndroidComponent PasswordStrengthEstimator passwordStrengthIndicator(); - CryptoComponent cryptoComponent(); - - DatabaseConfig databaseConfig(); - @DatabaseExecutor Executor databaseExecutor(); @@ -93,8 +87,6 @@ public interface AndroidComponent AndroidNotificationManager androidNotificationManager(); - SharedPreferences sharedPreferences(); - ScreenFilterMonitor screenFilterMonitor(); ConnectionRegistry connectionRegistry(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java index 762744e8a..92344f15c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java @@ -14,7 +14,6 @@ import android.widget.ProgressBar; import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.briar.R; -import org.briarproject.briar.android.Localizer; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BaseActivity; import org.briarproject.briar.android.controller.BriarController; @@ -111,8 +110,6 @@ public class PasswordActivity extends BaseActivity { private void deleteAccount() { accountManager.deleteAccount(); - Localizer.reinitialize(); - UiUtils.setTheme(this, getString(R.string.pref_theme_light_value)); setResult(RESULT_CANCELED); Intent i = new Intent(this, SetupActivity.class); i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); From b176ec5844ef49ea0262d4226501aba1062fdbe1 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 1 Aug 2018 15:56:53 +0100 Subject: [PATCH 16/18] Add TODO for account creation error handling. --- .../briarproject/briar/android/login/SetupControllerImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java index 2c5109739..e74f632b8 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java @@ -85,6 +85,7 @@ public class SetupControllerImpl extends PasswordControllerImpl new UiResultHandler(setupActivity) { @Override public void onResultUi(Boolean result) { + // TODO: Show an error if result is false if (setupActivity == null) throw new IllegalStateException(); setupActivity.showApp(); From 2a0ecc3f8084b54fcc75707f0055f47829065e42 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 1 Aug 2018 16:49:14 +0100 Subject: [PATCH 17/18] Clean up some tests. --- .../account/AccountManagerImplTest.java | 23 ++++--------------- .../login/PasswordControllerImplTest.java | 5 ++-- .../login/SetupControllerImplTest.java | 2 +- 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java index 998fa1c5e..66dcf9bdb 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java @@ -25,6 +25,7 @@ import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getTestDirectory; +import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.bramble.util.StringUtils.toHexString; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -41,8 +42,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 String password = "some.password"; - private final String newPassword = "some.new.password"; + private final String password = getRandomString(10); + private final String newPassword = getRandomString(10); private final File testDir = getTestDirectory(); private final File dbDir = new File(testDir, "db"); private final File keyDir = new File(testDir, "key"); @@ -66,21 +67,6 @@ public class AccountManagerImplTest extends BrambleMockTestCase { assertFalse(keyBackupFile.exists()); } - @Test - public void testCreatingAccountStoresDbKey() throws Exception { - context.checking(new Expectations() {{ - oneOf(crypto).generateSecretKey(); - will(returnValue(key)); - oneOf(crypto).encryptWithPassword(key.getBytes(), password); - will(returnValue(encryptedKey)); - }}); - - accountManager.createAccount(password); - - assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile)); - assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile)); - } - @Test public void testSignInReturnsFalseIfDbKeyCannotBeLoaded() { assertFalse(accountManager.signIn(password)); @@ -302,7 +288,8 @@ public class AccountManagerImplTest extends BrambleMockTestCase { } @Test - public void testChangePasswordReturnsTrueIfPasswordIsRight() throws Exception { + public void testChangePasswordReturnsTrueIfPasswordIsRight() + throws Exception { context.checking(new Expectations() {{ oneOf(crypto).decryptWithPassword(encryptedKey, password); will(returnValue(key.getBytes())); diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java index aa798f12b..987155ffc 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java @@ -12,6 +12,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; +import static org.briarproject.bramble.util.StringUtils.getRandomString; public class PasswordControllerImplTest extends BrambleMockTestCase { @@ -22,8 +23,8 @@ public class PasswordControllerImplTest extends BrambleMockTestCase { private final Executor ioExecutor = new ImmediateExecutor(); - private final String oldPassword = "some.old.pass"; - private final String newPassword = "some.new.pass"; + private final String oldPassword = getRandomString(10); + private final String newPassword = getRandomString(10); @Test public void testChangePasswordReturnsTrue() { diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java index 5c76733e8..51f6609c8 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java @@ -31,7 +31,7 @@ public class SetupControllerImplTest extends BrambleMockTestCase { private final Executor ioExecutor = new ImmediateExecutor(); private final String authorName = getRandomString(MAX_AUTHOR_NAME_LENGTH); - private final String password = "some.strong.pass"; + private final String password = getRandomString(10); private final LocalAuthor localAuthor = getLocalAuthor(); public SetupControllerImplTest() { From c1789a8e524f55bed26c23b8844a97358c473932 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 2 Aug 2018 09:51:17 +0100 Subject: [PATCH 18/18] Move identity creation into AccountManager. --- .../account/AndroidAccountManager.java | 6 +++-- .../account/AndroidAccountManagerTest.java | 5 +++- .../bramble/api/account/AccountManager.java | 23 +++++++++++-------- .../bramble/account/AccountManagerImpl.java | 11 +++++++-- .../account/AccountManagerImplTest.java | 15 ++++++++++-- .../bramble/account/BriarAccountManager.java | 6 +++-- .../android/login/SetupControllerImpl.java | 14 +++-------- .../login/SetupControllerImplTest.java | 14 ++--------- 8 files changed, 53 insertions(+), 41 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java index 9636c3dc0..f23e249ae 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java @@ -8,6 +8,7 @@ import android.preference.PreferenceManager; import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.util.IoUtils; import java.io.File; @@ -29,8 +30,9 @@ class AndroidAccountManager extends AccountManagerImpl @Inject AndroidAccountManager(DatabaseConfig databaseConfig, - CryptoComponent crypto, SharedPreferences prefs, Application app) { - super(databaseConfig, crypto); + CryptoComponent crypto, IdentityManager identityManager, + SharedPreferences prefs, Application app) { + super(databaseConfig, crypto, identityManager); this.prefs = prefs; appContext = app.getApplicationContext(); } diff --git a/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java b/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java index d283adcea..6736533a6 100644 --- a/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java +++ b/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java @@ -6,6 +6,7 @@ import android.content.pm.ApplicationInfo; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.test.BrambleMockTestCase; import org.jmock.Expectations; import org.jmock.lib.legacy.ClassImposteriser; @@ -32,6 +33,8 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase { private final DatabaseConfig databaseConfig = context.mock(DatabaseConfig.class); private final CryptoComponent crypto = context.mock(CryptoComponent.class); + private final IdentityManager identityManager = + context.mock(IdentityManager.class); private final SharedPreferences.Editor editor = context.mock(SharedPreferences.Editor.class); private final Application app; @@ -64,7 +67,7 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase { will(returnValue(app)); }}); accountManager = new AndroidAccountManager(databaseConfig, crypto, - prefs, app) { + identityManager, prefs, app) { @Override SharedPreferences getDefaultSharedPreferences() { return defaultPrefs; diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java index 5b475ae63..2e1b5a951 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java @@ -1,6 +1,7 @@ package org.briarproject.bramble.api.account; import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import javax.annotation.Nullable; @@ -10,17 +11,18 @@ public interface AccountManager { /** * Returns true if the manager has the database key. This will be false - * before {@link #createAccount(String)} or {@link #signIn(String)} has - * been called, and true after {@link #createAccount(String)} or - * {@link #signIn(String)} has returned true, until the process exits. + * before {@link #createAccount(String, String)} or {@link #signIn(String)} + * has been called, and true after {@link #createAccount(String, String)} + * or {@link #signIn(String)} has returned true, until the process exits. */ boolean hasDatabaseKey(); /** * Returns the database key if the manager has it. This will be null - * before {@link #createAccount(String)} or {@link #signIn(String)} has - * been called, and non-null after {@link #createAccount(String)} or - * {@link #signIn(String)} has returned true, until the process exits. + * before {@link #createAccount(String, String)} or {@link #signIn(String)} + * has been called, and non-null after + * {@link #createAccount(String, String)} or {@link #signIn(String)} has + * returned true, until the process exits. */ @Nullable SecretKey getDatabaseKey(); @@ -32,12 +34,15 @@ public interface AccountManager { boolean accountExists(); /** - * Creates a database key, encrypts it with the given password and stores - * it on disk. This method does not create the database directory, so + * Creates an identity with the given name and registers it with the + * {@link IdentityManager}. Creates a database key, encrypts it with the + * given password and stores it on disk. + *

+ * This method does not create the database directory, so * {@link #accountExists()} will continue to return false until the * database directory is created. */ - boolean createAccount(String password); + boolean createAccount(String name, String password); /** * Deletes all account state from disk. {@link #accountExists()} will diff --git a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java index 47ddd87f6..7eda4688b 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java @@ -4,6 +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.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; @@ -36,6 +38,7 @@ class AccountManagerImpl implements AccountManager { private final DatabaseConfig databaseConfig; private final CryptoComponent crypto; + private final IdentityManager identityManager; private final File dbKeyFile, dbKeyBackupFile; final Object stateChangeLock = new Object(); @@ -44,9 +47,11 @@ class AccountManagerImpl implements AccountManager { private volatile SecretKey databaseKey = null; @Inject - AccountManagerImpl(DatabaseConfig databaseConfig, CryptoComponent crypto) { + AccountManagerImpl(DatabaseConfig databaseConfig, CryptoComponent crypto, + IdentityManager identityManager) { this.databaseConfig = databaseConfig; this.crypto = crypto; + this.identityManager = identityManager; File keyDir = databaseConfig.getDatabaseKeyDirectory(); dbKeyFile = new File(keyDir, DB_KEY_FILENAME); dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME); @@ -152,8 +157,10 @@ class AccountManagerImpl implements AccountManager { } @Override - public boolean createAccount(String password) { + public boolean createAccount(String name, String password) { synchronized (stateChangeLock) { + LocalAuthor localAuthor = identityManager.createLocalAuthor(name); + identityManager.registerLocalAuthor(localAuthor); SecretKey key = crypto.generateSecretKey(); if (!encryptAndStoreDatabaseKey(key, password)) return false; databaseKey = key; diff --git a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java index 66dcf9bdb..84c5da72f 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java @@ -3,6 +3,8 @@ 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.IdentityManager; +import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.test.BrambleMockTestCase; import org.jmock.Expectations; import org.junit.After; @@ -22,6 +24,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.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getSecretKey; import static org.briarproject.bramble.test.TestUtils.getTestDirectory; @@ -36,12 +39,16 @@ public class AccountManagerImplTest extends BrambleMockTestCase { private final DatabaseConfig databaseConfig = context.mock(DatabaseConfig.class); private final CryptoComponent crypto = context.mock(CryptoComponent.class); + private final IdentityManager identityManager = + context.mock(IdentityManager.class); private final SecretKey key = getSecretKey(); private final byte[] encryptedKey = getRandomBytes(123); 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 String authorName = localAuthor.getName(); private final String password = getRandomString(10); private final String newPassword = getRandomString(10); private final File testDir = getTestDirectory(); @@ -61,7 +68,8 @@ public class AccountManagerImplTest extends BrambleMockTestCase { will(returnValue(keyDir)); }}); - accountManager = new AccountManagerImpl(databaseConfig, crypto); + accountManager = + new AccountManagerImpl(databaseConfig, crypto, identityManager); assertFalse(keyFile.exists()); assertFalse(keyBackupFile.exists()); @@ -243,6 +251,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(crypto).generateSecretKey(); will(returnValue(key)); oneOf(crypto).encryptWithPassword(key.getBytes(), password); @@ -251,7 +262,7 @@ public class AccountManagerImplTest extends BrambleMockTestCase { assertFalse(accountManager.hasDatabaseKey()); - assertTrue(accountManager.createAccount(password)); + assertTrue(accountManager.createAccount(authorName, password)); assertTrue(accountManager.hasDatabaseKey()); SecretKey dbKey = accountManager.getDatabaseKey(); diff --git a/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java b/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java index e1fee81cd..eb1e2faaa 100644 --- a/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java +++ b/briar-android/src/main/java/org/briarproject/bramble/account/BriarAccountManager.java @@ -5,6 +5,7 @@ import android.content.SharedPreferences; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.db.DatabaseConfig; +import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.briar.R; import org.briarproject.briar.android.Localizer; import org.briarproject.briar.android.util.UiUtils; @@ -15,8 +16,9 @@ class BriarAccountManager extends AndroidAccountManager { @Inject BriarAccountManager(DatabaseConfig databaseConfig, CryptoComponent crypto, - SharedPreferences prefs, Application app) { - super(databaseConfig, crypto, prefs, app); + IdentityManager identityManager, SharedPreferences prefs, + Application app) { + super(databaseConfig, crypto, identityManager, prefs, app); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java index e74f632b8..02f40226e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java @@ -4,8 +4,6 @@ import android.support.annotation.Nullable; import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; -import org.briarproject.bramble.api.identity.IdentityManager; -import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.briar.android.controller.handler.ResultHandler; @@ -23,18 +21,14 @@ public class SetupControllerImpl extends PasswordControllerImpl private static final Logger LOG = Logger.getLogger(SetupControllerImpl.class.getName()); - private final IdentityManager identityManager; - @Nullable private volatile SetupActivity setupActivity; @Inject SetupControllerImpl(AccountManager accountManager, @IoExecutor Executor ioExecutor, - PasswordStrengthEstimator strengthEstimator, - IdentityManager identityManager) { + PasswordStrengthEstimator strengthEstimator) { super(accountManager, ioExecutor, strengthEstimator); - this.identityManager = identityManager; } @Override @@ -104,10 +98,8 @@ public class SetupControllerImpl extends PasswordControllerImpl if (password == null) throw new IllegalStateException(); ioExecutor.execute(() -> { LOG.info("Creating account"); - LocalAuthor localAuthor = - identityManager.createLocalAuthor(authorName); - identityManager.registerLocalAuthor(localAuthor); - resultHandler.onResult(accountManager.createAccount(password)); + resultHandler.onResult(accountManager.createAccount(authorName, + password)); }); } } diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java index 51f6609c8..2ee6d0594 100644 --- a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java +++ b/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java @@ -2,8 +2,6 @@ package org.briarproject.briar.android.login; import org.briarproject.bramble.api.account.AccountManager; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; -import org.briarproject.bramble.api.identity.IdentityManager; -import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.ImmediateExecutor; import org.jmock.Expectations; @@ -15,7 +13,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import static junit.framework.Assert.assertTrue; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; -import static org.briarproject.bramble.test.TestUtils.getLocalAuthor; import static org.briarproject.bramble.util.StringUtils.getRandomString; public class SetupControllerImplTest extends BrambleMockTestCase { @@ -24,15 +21,12 @@ public class SetupControllerImplTest extends BrambleMockTestCase { context.mock(AccountManager.class); private final PasswordStrengthEstimator estimator = context.mock(PasswordStrengthEstimator.class); - private final IdentityManager identityManager = - context.mock(IdentityManager.class); private final SetupActivity setupActivity; private final Executor ioExecutor = new ImmediateExecutor(); private final String authorName = getRandomString(MAX_AUTHOR_NAME_LENGTH); private final String password = getRandomString(10); - private final LocalAuthor localAuthor = getLocalAuthor(); public SetupControllerImplTest() { context.setImposteriser(ClassImposteriser.INSTANCE); @@ -51,17 +45,13 @@ public class SetupControllerImplTest extends BrambleMockTestCase { will(returnValue(authorName)); oneOf(setupActivity).getPassword(); will(returnValue(password)); - // Create and register the local author - oneOf(identityManager).createLocalAuthor(authorName); - will(returnValue(localAuthor)); - oneOf(identityManager).registerLocalAuthor(localAuthor); // Create the account - oneOf(accountManager).createAccount(password); + oneOf(accountManager).createAccount(authorName, password); will(returnValue(true)); }}); SetupControllerImpl s = new SetupControllerImpl(accountManager, - ioExecutor, estimator, identityManager); + ioExecutor, estimator); s.setSetupActivity(setupActivity); AtomicBoolean called = new AtomicBoolean(false);