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..3c8519d89
--- /dev/null
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java
@@ -0,0 +1,39 @@
+package org.briarproject.bramble.api.account;
+
+import org.briarproject.bramble.api.crypto.CryptoExecutor;
+import org.briarproject.bramble.api.identity.IdentityManager;
+import org.briarproject.bramble.api.identity.LocalAuthor;
+import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+
+import javax.annotation.Nullable;
+
+@NotNullByDefault
+public interface AccountManager {
+
+ @CryptoExecutor
+ void createAccount(String name, String password);
+
+ AccountState getAccountState();
+
+ /**
+ * Returns the name of the {@link LocalAuthor} if it was just created and
+ * null otherwise.
+ *
+ * See {@link IdentityManager#getLocalAuthor()} for reliable retrieval.
+ */
+ @Nullable
+ String getCreatedLocalAuthorName();
+
+ /**
+ * Validates the account password and returns true if it was valid.
+ */
+ boolean validatePassword(String password);
+
+ /**
+ * Changes the password and returns true if successful, false otherwise.
+ */
+ @CryptoExecutor
+ boolean changePassword(String password, String newPassword);
+
+ void deleteAccount();
+}
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountState.java b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountState.java
new file mode 100644
index 000000000..2540c4d42
--- /dev/null
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountState.java
@@ -0,0 +1,12 @@
+package org.briarproject.bramble.api.account;
+
+public enum AccountState {
+
+ NO_ACCOUNT,
+ CREATING_ACCOUNT,
+ SIGNING_IN,
+ SIGNED_IN,
+ SIGNING_OUT,
+ SIGNED_OUT
+
+}
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-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..b77cfe71a
--- /dev/null
+++ b/bramble-core/src/main/java/org/briarproject/bramble/account/AccountManagerImpl.java
@@ -0,0 +1,127 @@
+package org.briarproject.bramble.account;
+
+
+import org.briarproject.bramble.api.account.AccountManager;
+import org.briarproject.bramble.api.account.AccountState;
+import org.briarproject.bramble.api.crypto.CryptoComponent;
+import org.briarproject.bramble.api.crypto.CryptoExecutor;
+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 java.util.logging.Logger;
+
+import javax.annotation.Nullable;
+
+import static java.util.logging.Level.INFO;
+import static org.briarproject.bramble.api.account.AccountState.CREATING_ACCOUNT;
+import static org.briarproject.bramble.api.account.AccountState.NO_ACCOUNT;
+import static org.briarproject.bramble.api.account.AccountState.SIGNED_IN;
+import static org.briarproject.bramble.api.account.AccountState.SIGNED_OUT;
+import static org.briarproject.bramble.util.LogUtils.logDuration;
+import static org.briarproject.bramble.util.LogUtils.now;
+
+@NotNullByDefault
+public abstract class AccountManagerImpl implements AccountManager {
+
+ private final static Logger LOG =
+ Logger.getLogger(AccountManagerImpl.class.getSimpleName());
+
+ protected final DatabaseConfig databaseConfig;
+ private final CryptoComponent crypto;
+ @Nullable
+ private volatile String nickname = null;
+
+ public AccountManagerImpl(CryptoComponent crypto,
+ DatabaseConfig databaseConfig) {
+ this.crypto = crypto;
+ this.databaseConfig = databaseConfig;
+ }
+
+ protected abstract boolean storeEncryptedDatabaseKey(String hex);
+
+ @Nullable
+ protected abstract String getEncryptedDatabaseKey();
+
+ private boolean hasEncryptedDatabaseKey() {
+ return getEncryptedDatabaseKey() != null;
+ }
+
+ @Override
+ @CryptoExecutor
+ public void createAccount(String name, String password) {
+ LOG.info("Setting local author name");
+ this.nickname = name;
+ SecretKey key = crypto.generateSecretKey();
+ databaseConfig.setEncryptionKey(key);
+ String hex = encryptDatabaseKey(key, password);
+ storeEncryptedDatabaseKey(hex);
+ }
+
+ @Override
+ public AccountState getAccountState() {
+ AccountState state;
+ if (!databaseConfig.databaseExists() && nickname != null &&
+ hasEncryptedDatabaseKey()) {
+ state = CREATING_ACCOUNT;
+ } else if (!hasEncryptedDatabaseKey()) {
+ state = NO_ACCOUNT;
+ } else if (databaseConfig.getEncryptionKey() == null) {
+ state = SIGNED_OUT;
+ } else {
+ state = SIGNED_IN;
+ }
+ // TODO SIGNING_IN, SIGNING_OUT, DELETING_ACCOUNT
+ if (LOG.isLoggable(INFO)) LOG.info("Account State: " + state.name());
+ return state;
+ }
+
+ @Nullable
+ @Override
+ public String getCreatedLocalAuthorName() {
+ String nickname = this.nickname;
+ if (LOG.isLoggable(INFO))
+ LOG.info("Local author name has been set: " + (nickname != null));
+ return nickname;
+ }
+
+ @CryptoExecutor
+ private 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);
+ }
+
+ @Override
+ public boolean validatePassword(String password) {
+ byte[] encrypted = getEncryptedKeyAsBytes();
+ byte[] key = crypto.decryptWithPassword(encrypted, password);
+ if (key == null) {
+ return false;
+ }
+ databaseConfig.setEncryptionKey(new SecretKey(key));
+ return true;
+ }
+
+ @Override
+ @CryptoExecutor
+ public boolean changePassword(String password, String newPassword) {
+ byte[] encrypted = getEncryptedKeyAsBytes();
+ byte[] key = crypto.decryptWithPassword(encrypted, password);
+ if (key == null) {
+ return false;
+ }
+ String hex = encryptDatabaseKey(new SecretKey(key), newPassword);
+ return storeEncryptedDatabaseKey(hex);
+ }
+
+ private byte[] getEncryptedKeyAsBytes() {
+ String hex = getEncryptedDatabaseKey();
+ if (hex == null)
+ throw new IllegalStateException("Encrypted database key is null");
+ return StringUtils.fromHexString(hex);
+ }
+
+}
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/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml
index 9ae75930b..6e5257ab7 100644
--- a/briar-android/src/main/AndroidManifest.xml
+++ b/briar-android/src/main/AndroidManifest.xml
@@ -70,7 +70,7 @@
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..cd9057f7e 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;
@@ -77,6 +78,8 @@ public interface AndroidComponent
DatabaseConfig databaseConfig();
+ AccountManager accountManager();
+
@DatabaseExecutor
Executor databaseExecutor();
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/AppModule.java b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java
index 3f953fd2c..b98757867 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
@@ -5,6 +5,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.os.StrictMode;
+import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
@@ -29,6 +30,7 @@ import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.bramble.plugin.tor.TorPluginFactory;
import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.StringUtils;
+import org.briarproject.briar.android.account.AndroidAccountManagerImpl;
import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.android.DozeWatchdog;
import org.briarproject.briar.api.android.ReferenceManager;
@@ -94,6 +96,13 @@ public class AppModule {
return databaseConfig;
}
+ @Provides
+ @Singleton
+ AccountManager provideAccountManager(
+ AndroidAccountManagerImpl androidAccountManager) {
+ return androidAccountManager;
+ }
+
@Provides
PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
@Scheduler ScheduledExecutorService scheduler,
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarApplication.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarApplication.java
index 6ab1c9ee0..eb41caddb 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/BriarApplication.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarApplication.java
@@ -1,5 +1,6 @@
package org.briarproject.briar.android;
+import android.content.Context;
import android.content.SharedPreferences;
import java.util.Collection;
@@ -15,5 +16,7 @@ public interface BriarApplication {
AndroidComponent getApplicationComponent();
+ Context getApplicationContext();
+
SharedPreferences getDefaultSharedPreferences();
}
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..9abb1fc12 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,8 @@ 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.account.AccountState;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
import org.briarproject.bramble.api.system.AndroidExecutor;
@@ -48,6 +49,8 @@ import static android.support.v4.app.NotificationCompat.PRIORITY_MIN;
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.api.account.AccountState.CREATING_ACCOUNT;
+import static org.briarproject.bramble.api.account.AccountState.SIGNED_IN;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_CHANNEL_ID;
@@ -75,7 +78,7 @@ public class BriarService extends Service {
private BroadcastReceiver receiver = null;
@Inject
- protected DatabaseConfig databaseConfig;
+ protected AccountManager accountManager;
// Fields that are accessed from background threads must be volatile
@Inject
protected volatile LifecycleManager lifecycleManager;
@@ -96,7 +99,8 @@ public class BriarService extends Service {
stopSelf();
return;
}
- if (databaseConfig.getEncryptionKey() == null) {
+ AccountState accountState = accountManager.getAccountState();
+ if (accountState != SIGNED_IN && accountState != CREATING_ACCOUNT) {
LOG.info("No database key");
stopSelf();
return;
@@ -141,7 +145,7 @@ public class BriarService extends Service {
nm.cancel(REMINDER_NOTIFICATION_ID);
// Start the services in a background thread
new Thread(() -> {
- String nickname = databaseConfig.getLocalAuthorName();
+ String nickname = accountManager.getCreatedLocalAuthorName();
StartResult result = lifecycleManager.startServices(nickname);
if (result == SUCCESS) {
started = true;
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/account/AndroidAccountManagerImpl.java
similarity index 76%
rename from briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/AndroidAccountManagerImpl.java
index 1e0bce3a2..f7ee1a5bc 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/AndroidAccountManagerImpl.java
@@ -1,12 +1,13 @@
-package org.briarproject.briar.android.controller;
+package org.briarproject.briar.android.account;
-import android.content.Context;
+import android.app.Application;
import android.content.SharedPreferences;
-import android.support.v7.preference.PreferenceManager;
+import org.briarproject.bramble.account.AccountManagerImpl;
+import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
-import org.briarproject.bramble.util.AndroidUtils;
+import org.briarproject.briar.android.BriarApplication;
import java.io.BufferedReader;
import java.io.File;
@@ -20,27 +21,30 @@ import javax.annotation.Nullable;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.util.AndroidUtils.deleteAppData;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
-public class ConfigControllerImpl implements ConfigController {
+public class AndroidAccountManagerImpl extends AccountManagerImpl {
- private static final Logger LOG =
- Logger.getLogger(ConfigControllerImpl.class.getName());
+ private final static Logger LOG =
+ Logger.getLogger(AndroidAccountManagerImpl.class.getSimpleName());
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 BriarApplication app;
+ private final SharedPreferences dbPrefs;
private final File dbKeyFile, dbKeyBackupFile;
- protected final DatabaseConfig databaseConfig;
@Inject
- public ConfigControllerImpl(SharedPreferences briarPrefs,
- DatabaseConfig databaseConfig) {
- this.briarPrefs = briarPrefs;
- this.databaseConfig = databaseConfig;
+ public AndroidAccountManagerImpl(CryptoComponent crypto,
+ DatabaseConfig databaseConfig, Application app,
+ SharedPreferences dbPrefs) {
+ super(crypto, databaseConfig);
+ this.app = (BriarApplication) app;
+ this.dbPrefs = dbPrefs;
File keyDir = databaseConfig.getDatabaseKeyDirectory();
dbKeyFile = new File(keyDir, DB_KEY_FILENAME);
dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME);
@@ -48,7 +52,7 @@ public class ConfigControllerImpl implements ConfigController {
@Override
@Nullable
- public String getEncryptedDatabaseKey() {
+ protected String getEncryptedDatabaseKey() {
String key = getDatabaseKeyFromPreferences();
if (key == null) key = getDatabaseKeyFromFile();
else migrateDatabaseKeyToFile(key);
@@ -57,7 +61,7 @@ public class ConfigControllerImpl implements ConfigController {
@Nullable
private String getDatabaseKeyFromPreferences() {
- String key = briarPrefs.getString(PREF_DB_KEY, null);
+ String key = dbPrefs.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;
@@ -97,7 +101,7 @@ public class ConfigControllerImpl implements ConfigController {
private void migrateDatabaseKeyToFile(String key) {
if (storeEncryptedDatabaseKey(key)) {
- if (briarPrefs.edit().remove(PREF_DB_KEY).commit())
+ if (dbPrefs.edit().remove(PREF_DB_KEY).commit())
LOG.info("Database key migrated to file");
else LOG.warning("Database key not removed from preferences");
} else {
@@ -106,7 +110,7 @@ public class ConfigControllerImpl implements ConfigController {
}
@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())
@@ -151,21 +155,10 @@ public class ConfigControllerImpl implements ConfigController {
}
@Override
- public void deleteAccount(Context ctx) {
+ public void deleteAccount() {
LOG.info("Deleting account");
- SharedPreferences defaultPrefs =
- PreferenceManager.getDefaultSharedPreferences(ctx);
- AndroidUtils.deleteAppData(ctx, briarPrefs, defaultPrefs);
+ SharedPreferences defaultPrefs = app.getDefaultSharedPreferences();
+ deleteAppData(app.getApplicationContext(), dbPrefs, defaultPrefs);
}
- @Override
- public boolean accountExists() {
- String hex = getEncryptedDatabaseKey();
- return hex != null && databaseConfig.databaseExists();
- }
-
- @Override
- public boolean accountSignedIn() {
- return databaseConfig.getEncryptionKey() != null;
- }
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/AuthorNameFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/account/AuthorNameFragment.java
similarity index 98%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/AuthorNameFragment.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/AuthorNameFragment.java
index 6e4c35d86..c303c9739 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/AuthorNameFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/AuthorNameFragment.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.os.Bundle;
import android.support.design.widget.TextInputEditText;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/DozeFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/account/DozeFragment.java
similarity index 96%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/DozeFragment.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/DozeFragment.java
index 624437c6d..90e820748 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/DozeFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/DozeFragment.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.annotation.SuppressLint;
import android.content.Intent;
@@ -13,8 +13,8 @@ import android.widget.ProgressBar;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
+import org.briarproject.briar.android.account.PowerView.OnCheckedChangedListener;
import org.briarproject.briar.android.activity.ActivityComponent;
-import org.briarproject.briar.android.login.PowerView.OnCheckedChangedListener;
import org.briarproject.briar.android.util.UiUtils;
import static android.view.View.INVISIBLE;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/DozeView.java b/briar-android/src/main/java/org/briarproject/briar/android/account/DozeView.java
similarity index 96%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/DozeView.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/DozeView.java
index a2b1c5186..e02f4f2e5 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/DozeView.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/DozeView.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.content.Context;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/HuaweiView.java b/briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiView.java
similarity index 97%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/HuaweiView.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiView.java
index c566ce697..2396aab25 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/HuaweiView.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiView.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.content.Context;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/account/PasswordFragment.java
similarity index 97%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/PasswordFragment.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/PasswordFragment.java
index 49c90239c..400a56d6c 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/PasswordFragment.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.os.Bundle;
import android.os.IBinder;
@@ -15,6 +15,7 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
+import org.briarproject.briar.android.login.StrengthMeter;
import org.briarproject.briar.android.util.UiUtils;
import javax.annotation.Nullable;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PowerView.java b/briar-android/src/main/java/org/briarproject/briar/android/account/PowerView.java
similarity index 98%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/PowerView.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/PowerView.java
index ffcaf3409..032826ca5 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/PowerView.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/PowerView.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.content.Context;
import android.os.Parcel;
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/account/SetupActivity.java
similarity index 96%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/SetupActivity.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java
index f91c57512..e655b6faa 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.annotation.TargetApi;
import android.content.Intent;
@@ -10,6 +10,7 @@ import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BaseActivity;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
+import org.briarproject.briar.android.login.OpenDatabaseActivity;
import javax.annotation.Nullable;
import javax.inject.Inject;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupController.java b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupController.java
similarity index 85%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/SetupController.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/SetupController.java
index 392151897..6df870ab6 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupController.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupController.java
@@ -1,6 +1,7 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+import org.briarproject.briar.android.login.PasswordController;
@NotNullByDefault
public interface SetupController extends PasswordController {
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/account/SetupControllerImpl.java
similarity index 84%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/SetupControllerImpl.java
index 3923cce4a..cf86f0d88 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupControllerImpl.java
@@ -1,16 +1,15 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
-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;
-import org.briarproject.bramble.api.crypto.SecretKey;
-import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.android.controller.handler.ResultHandler;
import org.briarproject.briar.android.controller.handler.UiResultHandler;
+import org.briarproject.briar.android.login.PasswordControllerImpl;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
@@ -28,11 +27,10 @@ public class SetupControllerImpl extends PasswordControllerImpl
private volatile SetupActivity setupActivity;
@Inject
- SetupControllerImpl(SharedPreferences briarPrefs,
- DatabaseConfig databaseConfig,
+ SetupControllerImpl(AccountManager accountManager,
@CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto,
PasswordStrengthEstimator strengthEstimator) {
- super(briarPrefs, databaseConfig, cryptoExecutor, crypto,
+ super(accountManager, cryptoExecutor, crypto,
strengthEstimator);
}
@@ -102,11 +100,7 @@ public class SetupControllerImpl extends PasswordControllerImpl
if (password == null) throw new IllegalStateException();
cryptoExecutor.execute(() -> {
LOG.info("Creating account");
- databaseConfig.setLocalAuthorName(authorName);
- SecretKey key = crypto.generateSecretKey();
- databaseConfig.setEncryptionKey(key);
- String hex = encryptDatabaseKey(key, password);
- storeEncryptedDatabaseKey(hex);
+ accountManager.createAccount(authorName, password);
resultHandler.onResult(null);
});
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupFragment.java
similarity index 92%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/SetupFragment.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/SetupFragment.java
index 5d3fce362..f12682f39 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupFragment.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.text.Editable;
import android.text.TextWatcher;
@@ -17,7 +17,7 @@ import javax.inject.Inject;
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
-abstract class SetupFragment extends BaseFragment implements TextWatcher,
+public abstract class SetupFragment extends BaseFragment implements TextWatcher,
OnEditorActionListener, OnClickListener {
@Inject
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
index 1d92a31f3..3abe3c7ef 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
@@ -30,13 +30,13 @@ import org.briarproject.briar.android.keyagreement.ContactExchangeActivity;
import org.briarproject.briar.android.keyagreement.IntroFragment;
import org.briarproject.briar.android.keyagreement.KeyAgreementActivity;
import org.briarproject.briar.android.keyagreement.KeyAgreementFragment;
-import org.briarproject.briar.android.login.AuthorNameFragment;
+import org.briarproject.briar.android.account.AuthorNameFragment;
import org.briarproject.briar.android.login.ChangePasswordActivity;
-import org.briarproject.briar.android.login.DozeFragment;
+import org.briarproject.briar.android.account.DozeFragment;
import org.briarproject.briar.android.login.OpenDatabaseActivity;
import org.briarproject.briar.android.login.PasswordActivity;
-import org.briarproject.briar.android.login.PasswordFragment;
-import org.briarproject.briar.android.login.SetupActivity;
+import org.briarproject.briar.android.account.PasswordFragment;
+import org.briarproject.briar.android.account.SetupActivity;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.panic.PanicPreferencesActivity;
import org.briarproject.briar.android.panic.PanicResponderActivity;
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..970e210e6 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,14 +4,12 @@ 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;
import org.briarproject.briar.android.login.PasswordControllerImpl;
-import org.briarproject.briar.android.login.SetupController;
-import org.briarproject.briar.android.login.SetupControllerImpl;
+import org.briarproject.briar.android.account.SetupController;
+import org.briarproject.briar.android.account.SetupControllerImpl;
import org.briarproject.briar.android.navdrawer.NavDrawerController;
import org.briarproject.briar.android.navdrawer.NavDrawerControllerImpl;
@@ -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/activity/BriarActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java
index 3d2d8361c..6d6469f5e 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.signedIn() && !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.signedIn()) {
// 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..1a37a94f8 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 signedIn();
/**
* 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..291418cb5 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,8 @@ 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.account.AccountState;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.settings.Settings;
@@ -21,6 +22,8 @@ import java.util.logging.Logger;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.api.account.AccountState.CREATING_ACCOUNT;
+import static org.briarproject.bramble.api.account.AccountState.SIGNED_IN;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE;
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
@@ -33,7 +36,7 @@ public class BriarControllerImpl implements BriarController {
public static final String DOZE_ASK_AGAIN = "dozeAskAgain";
private final BriarServiceConnection serviceConnection;
- private final DatabaseConfig databaseConfig;
+ private final AccountManager accountManager;
@DatabaseExecutor
private final Executor databaseExecutor;
private final SettingsManager settingsManager;
@@ -44,12 +47,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 +62,7 @@ public class BriarControllerImpl implements BriarController {
@Override
@CallSuper
public void onActivityCreate(Activity activity) {
- if (databaseConfig.getEncryptionKey() != null) startAndBindService();
+ if (signedIn()) startAndBindService();
}
@Override
@@ -84,8 +87,9 @@ public class BriarControllerImpl implements BriarController {
}
@Override
- public boolean hasEncryptionKey() {
- return databaseConfig.getEncryptionKey() != null;
+ public boolean signedIn() {
+ AccountState state = accountManager.getAccountState();
+ return state == CREATING_ACCOUNT || state == SIGNED_IN;
}
@Override
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 e19452a9c..000000000
--- a/briar-android/src/main/java/org/briarproject/briar/android/controller/ConfigController.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.briarproject.briar.android.controller;
-
-import android.content.Context;
-
-import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
-
-import javax.annotation.Nullable;
-
-@NotNullByDefault
-public interface ConfigController {
-
- @Nullable
- String getEncryptedDatabaseKey();
-
- boolean storeEncryptedDatabaseKey(String hex);
-
- void deleteAccount(Context ctx);
-
- boolean accountExists();
-
- boolean accountSignedIn();
-
-}
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..5c8144c5a 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,6 +14,7 @@ import android.widget.ProgressBar;
import org.briarproject.briar.R;
import org.briarproject.briar.android.Localizer;
+import org.briarproject.briar.android.account.SetupActivity;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BaseActivity;
import org.briarproject.briar.android.controller.BriarController;
@@ -85,7 +86,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.signedIn()) {
setResult(RESULT_OK);
finish();
}
@@ -105,7 +106,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/PasswordController.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordController.java
index ec3cb7ed7..68f44ebeb 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,12 @@
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 {
+
+ boolean accountExists();
float estimatePasswordStrength(String password);
@@ -15,4 +16,6 @@ public interface PasswordController extends ConfigController {
void changePassword(String password, String newPassword,
ResultHandler resultHandler);
+ void deleteAccount();
+
}
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..403f5b324 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,47 +1,41 @@
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;
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;
+import static org.briarproject.bramble.api.account.AccountState.NO_ACCOUNT;
@NotNullByDefault
-public class PasswordControllerImpl extends ConfigControllerImpl
- implements PasswordController {
-
- private static final Logger LOG =
- Logger.getLogger(PasswordControllerImpl.class.getName());
+public class PasswordControllerImpl implements PasswordController {
+ protected final AccountManager accountManager;
protected final Executor cryptoExecutor;
protected final CryptoComponent crypto;
private final PasswordStrengthEstimator strengthEstimator;
@Inject
- PasswordControllerImpl(SharedPreferences briarPrefs,
- DatabaseConfig databaseConfig,
+ public PasswordControllerImpl(AccountManager accountManager,
@CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto,
PasswordStrengthEstimator strengthEstimator) {
- super(briarPrefs, databaseConfig);
+ this.accountManager = accountManager;
this.cryptoExecutor = cryptoExecutor;
this.crypto = crypto;
this.strengthEstimator = strengthEstimator;
}
+ @Override
+ public boolean accountExists() {
+ return accountManager.getAccountState() != NO_ACCOUNT;
+ }
+
@Override
public float estimatePasswordStrength(String password) {
return strengthEstimator.estimateStrength(password);
@@ -50,46 +44,25 @@ public class PasswordControllerImpl extends ConfigControllerImpl
@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 {
- databaseConfig.setEncryptionKey(new SecretKey(key));
- resultHandler.onResult(true);
- }
+ boolean result = accountManager.validatePassword(password);
+ resultHandler.onResult(result);
});
}
@Override
public void changePassword(String password, 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);
- resultHandler.onResult(storeEncryptedDatabaseKey(hex));
- }
+ boolean result =
+ accountManager.changePassword(password, newPassword);
+ resultHandler.onResult(result);
});
}
- private byte[] getEncryptedKey() {
- String hex = getEncryptedDatabaseKey();
- if (hex == null)
- throw new IllegalStateException("Encrypted database key is null");
- return StringUtils.fromHexString(hex);
+ @Override
+ public void deleteAccount() {
+ accountManager.deleteAccount();
}
- @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/SignInReminderReceiver.java b/briar-android/src/main/java/org/briarproject/briar/android/login/SignInReminderReceiver.java
index e361aeb6e..f6bec0821 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;
@@ -28,6 +28,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.Build.VERSION.SDK_INT;
import static android.support.v4.app.NotificationCompat.PRIORITY_LOW;
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
+import static org.briarproject.bramble.api.account.AccountState.NO_ACCOUNT;
import static org.briarproject.briar.android.TestingConstants.FEATURE_FLAG_SIGN_IN_REMINDER;
import static org.briarproject.briar.android.settings.SettingsActivity.NO_NOTIFY_SIGN_IN;
import static org.briarproject.briar.android.settings.SettingsFragment.NOTIFY_SIGN_IN;
@@ -37,7 +38,7 @@ import static org.briarproject.briar.api.android.AndroidNotificationManager.REMI
public class SignInReminderReceiver extends BroadcastReceiver {
@Inject
- DatabaseConfig databaseConfig;
+ AccountManager accountManager;
@Override
public void onReceive(Context ctx, Intent intent) {
@@ -51,7 +52,7 @@ public class SignInReminderReceiver extends BroadcastReceiver {
if (action == null) return;
if (action.equals(ACTION_BOOT_COMPLETED) ||
action.equals(ACTION_MY_PACKAGE_REPLACED)) {
- if (databaseConfig.databaseExists()) {
+ if (accountManager.getAccountState() != NO_ACCOUNT) {
SharedPreferences prefs = app.getDefaultSharedPreferences();
if (prefs.getBoolean(NOTIFY_SIGN_IN, true)) {
showSignInNotification(ctx);
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..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(PanicResponderActivity.this);
+ 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 d207508a4..b2d61d882 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,18 +7,20 @@ 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.account.SetupActivity;
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;
import java.util.logging.Logger;
import javax.inject.Inject;
+import static org.briarproject.bramble.api.account.AccountState.NO_ACCOUNT;
+import static org.briarproject.bramble.api.account.AccountState.SIGNED_IN;
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
public class SplashScreenActivity extends BaseActivity {
@@ -27,7 +29,7 @@ public class SplashScreenActivity extends BaseActivity {
Logger.getLogger(SplashScreenActivity.class.getName());
@Inject
- protected ConfigController configController;
+ AccountManager accountManager;
@Inject
protected AndroidExecutor androidExecutor;
@@ -43,7 +45,7 @@ public class SplashScreenActivity extends BaseActivity {
setContentView(R.layout.splash);
- if (configController.accountSignedIn()) {
+ if (accountManager.getAccountState() == SIGNED_IN) {
startActivity(new Intent(this, OpenDatabaseActivity.class));
finish();
} else {
@@ -64,12 +66,12 @@ public class SplashScreenActivity extends BaseActivity {
LOG.info("Expired");
startActivity(new Intent(this, ExpiredActivity.class));
} else {
- if (configController.accountExists()) {
+ if (accountManager.getAccountState() != NO_ACCOUNT) {
LOG.info("Account exists");
startActivity(new Intent(this, OpenDatabaseActivity.class));
} else {
LOG.info("Account does not exist");
- configController.deleteAccount(this);
+ accountManager.deleteAccount();
startActivity(new Intent(this, SetupActivity.class));
}
}
diff --git a/briar-android/src/test/java/org/briarproject/briar/android/account/AndroidAccountManagerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/account/AndroidAccountManagerImplTest.java
new file mode 100644
index 000000000..6d665085e
--- /dev/null
+++ b/briar-android/src/test/java/org/briarproject/briar/android/account/AndroidAccountManagerImplTest.java
@@ -0,0 +1,368 @@
+package org.briarproject.briar.android.account;
+
+import android.app.Application;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+
+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;
+import org.junit.After;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+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.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
+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.briarproject.briar.android.TestDatabaseKeyUtils.loadDatabaseKey;
+import static org.briarproject.briar.android.TestDatabaseKeyUtils.storeDatabaseKey;
+import static org.hamcrest.Matchers.samePropertyValuesAs;
+
+public class AndroidAccountManagerImplTest extends BrambleMockTestCase {
+
+ private final CryptoComponent cryptoComponent =
+ context.mock(CryptoComponent.class);
+ private final SharedPreferences prefs =
+ context.mock(SharedPreferences.class);
+ private final DatabaseConfig databaseConfig =
+ context.mock(DatabaseConfig.class);
+ private final Editor editor = context.mock(Editor.class);
+
+ private final String authorName = getRandomString(MAX_AUTHOR_NAME_LENGTH);
+ private final String password = "some.strong.pass";
+ private final String oldPassword = "some.old.pass";
+ private final String newPassword = "some.new.pass";
+ private final SecretKey key = getSecretKey();
+ private final byte[] keyBytes = key.getBytes();
+ private final byte[] encryptedKey = getRandomBytes(123);
+ private final String encryptedKeyHex = toHexString(encryptedKey);
+ private final String oldEncryptedKeyHex = toHexString(getRandomBytes(123));
+ private final byte[] oldEncryptedKey = getRandomBytes(123);
+ private final byte[] newEncryptedKey = 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");
+
+ @Test
+ public void createAccount() throws IOException {
+ context.checking(new Expectations() {{
+ // Generate a database key
+ oneOf(cryptoComponent).generateSecretKey();
+ will(returnValue(key));
+ // Attach the author name and database key to the database config
+ oneOf(databaseConfig).setEncryptionKey(key);
+ // Encrypt the key with the password
+ oneOf(cryptoComponent)
+ .encryptWithPassword(key.getBytes(), password);
+ will(returnValue(encryptedKey));
+ // Store the encrypted key
+ allowing(databaseConfig).getDatabaseKeyDirectory();
+ will(returnValue(keyDir));
+ }});
+ getAndroidAccountManagerImpl().createAccount(authorName, password);
+
+ assertTrue(keyFile.exists());
+ assertTrue(keyBackupFile.exists());
+ assertEquals(toHexString(encryptedKey), loadDatabaseKey(keyFile));
+ assertEquals(toHexString(encryptedKey), loadDatabaseKey(keyBackupFile));
+ }
+
+ @Test
+ public void testChangePasswordReturnsTrue() throws Exception {
+ context.checking(new Expectations() {{
+ // Look up the encrypted DB key
+ oneOf(prefs).getString("key", null);
+ will(returnValue(null));
+ allowing(databaseConfig).getDatabaseKeyDirectory();
+ will(returnValue(keyDir));
+ // Decrypt and re-encrypt the key
+ oneOf(cryptoComponent)
+ .decryptWithPassword(oldEncryptedKey, oldPassword);
+ will(returnValue(key.getBytes()));
+ oneOf(cryptoComponent)
+ .encryptWithPassword(key.getBytes(), newPassword);
+ will(returnValue(newEncryptedKey));
+ }});
+
+ assertFalse(keyFile.exists());
+ assertFalse(keyBackupFile.exists());
+
+ storeDatabaseKey(keyFile, toHexString(oldEncryptedKey));
+ storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey));
+
+ AndroidAccountManagerImpl accountManager =
+ getAndroidAccountManagerImpl();
+ assertTrue(accountManager.changePassword(oldPassword, newPassword));
+
+ assertTrue(keyFile.exists());
+ assertTrue(keyBackupFile.exists());
+ assertEquals(toHexString(newEncryptedKey), loadDatabaseKey(keyFile));
+ assertEquals(toHexString(newEncryptedKey),
+ loadDatabaseKey(keyBackupFile));
+ }
+
+ @Test
+ public void testChangePasswordReturnsFalseIfOldPasswordIsWrong()
+ throws Exception {
+ context.checking(new Expectations() {{
+ // Look up the encrypted DB key
+ oneOf(prefs).getString("key", null);
+ will(returnValue(null));
+ allowing(databaseConfig).getDatabaseKeyDirectory();
+ will(returnValue(keyDir));
+ // Try to decrypt the key - the password is wrong
+ oneOf(cryptoComponent)
+ .decryptWithPassword(oldEncryptedKey, oldPassword);
+ will(returnValue(null));
+ }});
+
+ assertFalse(keyFile.exists());
+ assertFalse(keyBackupFile.exists());
+
+ storeDatabaseKey(keyFile, toHexString(oldEncryptedKey));
+ storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey));
+
+ AndroidAccountManagerImpl accountManager =
+ getAndroidAccountManagerImpl();
+ assertFalse(accountManager.changePassword(oldPassword, newPassword));
+
+ assertTrue(keyFile.exists());
+ assertTrue(keyBackupFile.exists());
+ assertEquals(toHexString(oldEncryptedKey), loadDatabaseKey(keyFile));
+ assertEquals(toHexString(oldEncryptedKey),
+ loadDatabaseKey(keyBackupFile));
+ }
+
+ @Test
+ public void testValidatePasswordReturnsTrue() throws Exception {
+ context.checking(new Expectations() {{
+ // Look up the encrypted DB key
+ oneOf(prefs).getString("key", null);
+ will(returnValue(null));
+ allowing(databaseConfig).getDatabaseKeyDirectory();
+ will(returnValue(keyDir));
+ // Decrypt the key
+ oneOf(cryptoComponent)
+ .decryptWithPassword(encryptedKey, password);
+ will(returnValue(keyBytes));
+ oneOf(databaseConfig)
+ .setEncryptionKey(with(samePropertyValuesAs(key)));
+ }});
+
+ assertFalse(keyFile.exists());
+ assertFalse(keyBackupFile.exists());
+
+ storeDatabaseKey(keyFile, toHexString(encryptedKey));
+ storeDatabaseKey(keyBackupFile, toHexString(encryptedKey));
+
+ AndroidAccountManagerImpl accountManager =
+ getAndroidAccountManagerImpl();
+ assertTrue(accountManager.validatePassword(password));
+ }
+
+ @Test
+ public void testValidatePasswordReturnsFalseIfPasswordIsWrong()
+ throws Exception {
+ context.checking(new Expectations() {{
+ // Look up the encrypted DB key
+ oneOf(prefs).getString("key", null);
+ will(returnValue(null));
+ allowing(databaseConfig).getDatabaseKeyDirectory();
+ will(returnValue(keyDir));
+ // Decrypt the key
+ oneOf(cryptoComponent)
+ .decryptWithPassword(encryptedKey, password);
+ will(returnValue(null));
+ }});
+
+ assertFalse(keyFile.exists());
+ assertFalse(keyBackupFile.exists());
+
+ storeDatabaseKey(keyFile, toHexString(encryptedKey));
+ storeDatabaseKey(keyBackupFile, toHexString(encryptedKey));
+
+ AndroidAccountManagerImpl accountManager =
+ getAndroidAccountManagerImpl();
+ assertFalse(accountManager.validatePassword(password));
+ }
+
+ @Test
+ public void testDbKeyIsMigratedFromPreferencesToFile() throws Exception {
+ context.checking(new Expectations() {{
+ oneOf(prefs).getString("key", null);
+ will(returnValue(encryptedKeyHex));
+ allowing(databaseConfig).getDatabaseKeyDirectory();
+ will(returnValue(keyDir));
+ 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());
+
+ AndroidAccountManagerImpl c = getAndroidAccountManagerImpl();
+
+ 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));
+
+ AndroidAccountManagerImpl c = getAndroidAccountManagerImpl();
+
+ 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));
+
+ AndroidAccountManagerImpl c = getAndroidAccountManagerImpl();
+
+ 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());
+
+ AndroidAccountManagerImpl c = getAndroidAccountManagerImpl();
+
+ 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));
+
+ AndroidAccountManagerImpl c = getAndroidAccountManagerImpl();
+
+ 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));
+
+ AndroidAccountManagerImpl c = getAndroidAccountManagerImpl();
+
+ assertTrue(c.storeEncryptedDatabaseKey(encryptedKeyHex));
+
+ assertTrue(keyFile.exists());
+ assertTrue(keyBackupFile.exists());
+ assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
+ assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
+ }
+
+ @After
+ public void tearDown() {
+ deleteTestDirectory(testDir);
+ }
+
+ private AndroidAccountManagerImpl getAndroidAccountManagerImpl() {
+ // app is only needed for deleting account
+ Application app = null;
+ //noinspection ConstantConditions
+ return new AndroidAccountManagerImpl(cryptoComponent, databaseConfig,
+ app, prefs);
+ }
+}
diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordFragmentTest.java b/briar-android/src/test/java/org/briarproject/briar/android/account/PasswordFragmentTest.java
similarity index 97%
rename from briar-android/src/test/java/org/briarproject/briar/android/login/PasswordFragmentTest.java
rename to briar-android/src/test/java/org/briarproject/briar/android/account/PasswordFragmentTest.java
index 4ddc21cc9..9985a93c4 100644
--- a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordFragmentTest.java
+++ b/briar-android/src/test/java/org/briarproject/briar/android/account/PasswordFragmentTest.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.support.design.widget.TextInputLayout;
import android.view.View;
@@ -7,6 +7,7 @@ import android.widget.EditText;
import org.briarproject.briar.R;
import org.briarproject.briar.android.TestBriarApplication;
+import org.briarproject.briar.android.login.StrengthMeter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupActivityTest.java b/briar-android/src/test/java/org/briarproject/briar/android/account/SetupActivityTest.java
similarity index 93%
rename from briar-android/src/test/java/org/briarproject/briar/android/login/SetupActivityTest.java
rename to briar-android/src/test/java/org/briarproject/briar/android/account/SetupActivityTest.java
index e01220686..8723dfc22 100644
--- a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupActivityTest.java
+++ b/briar-android/src/test/java/org/briarproject/briar/android/account/SetupActivityTest.java
@@ -1,10 +1,11 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.support.design.widget.TextInputLayout;
import android.widget.EditText;
import org.briarproject.briar.R;
import org.briarproject.briar.android.TestBriarApplication;
+import org.briarproject.briar.android.account.SetupActivity;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
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/account/SetupControllerImplTest.java
similarity index 66%
rename from briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java
rename to briar-android/src/test/java/org/briarproject/briar/android/account/SetupControllerImplTest.java
index b0df4cde8..bd0ed5678 100644
--- a/briar-android/src/test/java/org/briarproject/briar/android/login/SetupControllerImplTest.java
+++ b/briar-android/src/test/java/org/briarproject/briar/android/account/SetupControllerImplTest.java
@@ -1,11 +1,10 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
-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;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.ImmediateExecutor;
@@ -18,22 +17,17 @@ 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.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 {
- 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);
@@ -45,8 +39,6 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
private final String authorName = getRandomString(MAX_AUTHOR_NAME_LENGTH);
private final String password = "some.strong.pass";
- private final byte[] encryptedKey = getRandomBytes(123);
- 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");
@@ -74,25 +66,15 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
will(returnValue(authorName));
oneOf(setupActivity).getPassword();
will(returnValue(password));
- // 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));
+ oneOf(accountManager).createAccount(authorName, password);
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
- SetupControllerImpl s = new SetupControllerImpl(briarPrefs,
- databaseConfig, cryptoExecutor, crypto, estimator);
+ SetupControllerImpl s =
+ new SetupControllerImpl(accountManager, cryptoExecutor, crypto,
+ estimator);
s.setSetupActivity(setupActivity);
AtomicBoolean called = new AtomicBoolean(false);
@@ -100,11 +82,6 @@ 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
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 859792b3c..000000000
--- a/briar-android/src/test/java/org/briarproject/briar/android/controller/ConfigControllerImplTest.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package org.briarproject.briar.android.controller;
-
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-
-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 {
-
- private final SharedPreferences prefs =
- context.mock(SharedPreferences.class);
- private final DatabaseConfig databaseConfig =
- 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");
-
- @Test
- public void testDbKeyIsMigratedFromPreferencesToFile() throws Exception {
- context.checking(new Expectations() {{
- oneOf(prefs).getString("key", null);
- will(returnValue(encryptedKeyHex));
- allowing(databaseConfig).getDatabaseKeyDirectory();
- will(returnValue(keyDir));
- 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());
-
- ConfigControllerImpl c = new ConfigControllerImpl(prefs,
- 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,
- 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,
- 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,
- 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,
- 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,
- 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/forum/TestForumActivity.java b/briar-android/src/test/java/org/briarproject/briar/android/forum/TestForumActivity.java
index 72b8d6644..29397a0de 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.signedIn()).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..639a59ae2 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,37 +1,23 @@
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;
-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 {
- private final SharedPreferences briarPrefs =
- context.mock(SharedPreferences.class);
- private final DatabaseConfig databaseConfig =
- context.mock(DatabaseConfig.class);
+ private final AccountManager accountManager =
+ context.mock(AccountManager.class);
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
private final PasswordStrengthEstimator estimator =
context.mock(PasswordStrengthEstimator.class);
@@ -40,85 +26,37 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
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 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");
@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));
- // Decrypt and re-encrypt the key
- oneOf(crypto).decryptWithPassword(oldEncryptedKey, oldPassword);
- will(returnValue(key));
- oneOf(crypto).encryptWithPassword(key, newPassword);
- will(returnValue(newEncryptedKey));
+ oneOf(accountManager).changePassword(oldPassword, newPassword);
+ will(returnValue(true));
}});
- assertFalse(keyFile.exists());
- assertFalse(keyBackupFile.exists());
-
- storeDatabaseKey(keyFile, toHexString(oldEncryptedKey));
- storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey));
-
- PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
- databaseConfig, cryptoExecutor, crypto, estimator);
+ PasswordControllerImpl p =
+ new PasswordControllerImpl(accountManager, cryptoExecutor,
+ crypto, estimator);
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));
- // 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));
}});
- assertFalse(keyFile.exists());
- assertFalse(keyBackupFile.exists());
-
- storeDatabaseKey(keyFile, toHexString(oldEncryptedKey));
- storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey));
-
- PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
- databaseConfig, cryptoExecutor, crypto, estimator);
+ PasswordControllerImpl p =
+ new PasswordControllerImpl(accountManager, cryptoExecutor,
+ crypto, estimator);
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);
- }
}