mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Compare commits
3 Commits
priority-e
...
1341-accou
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51cf49da19 | ||
|
|
9892199305 | ||
|
|
b28307002e |
@@ -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();
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
|
}
|
||||||
@@ -21,10 +21,5 @@ public interface DatabaseConfig {
|
|||||||
@Nullable
|
@Nullable
|
||||||
SecretKey getEncryptionKey();
|
SecretKey getEncryptionKey();
|
||||||
|
|
||||||
void setLocalAuthorName(String nickname);
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
String getLocalAuthorName();
|
|
||||||
|
|
||||||
long getMaxSize();
|
long getMaxSize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -46,16 +46,6 @@ public class TestDatabaseConfig implements DatabaseConfig {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setLocalAuthorName(String nickname) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getLocalAuthorName() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getMaxSize() {
|
public long getMaxSize() {
|
||||||
return maxSize;
|
return maxSize;
|
||||||
|
|||||||
@@ -26,10 +26,11 @@
|
|||||||
android:theme="@style/BriarTheme">
|
android:theme="@style/BriarTheme">
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name="org.briarproject.briar.android.BootReceiver"
|
android:name="org.briarproject.briar.android.login.SignInReminderReceiver"
|
||||||
android:exported="false">
|
android:exported="false">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||||
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="org.briarproject.briar.android.login.SetupActivity"
|
android:name="org.briarproject.briar.android.account.SetupActivity"
|
||||||
android:label="@string/setup_title"
|
android:label="@string/setup_title"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
</activity>
|
</activity>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.content.SharedPreferences;
|
|||||||
import org.briarproject.bramble.BrambleAndroidModule;
|
import org.briarproject.bramble.BrambleAndroidModule;
|
||||||
import org.briarproject.bramble.BrambleCoreEagerSingletons;
|
import org.briarproject.bramble.BrambleCoreEagerSingletons;
|
||||||
import org.briarproject.bramble.BrambleCoreModule;
|
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.ContactExchangeTask;
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
@@ -26,6 +27,7 @@ import org.briarproject.bramble.api.system.AndroidExecutor;
|
|||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.briar.BriarCoreEagerSingletons;
|
import org.briarproject.briar.BriarCoreEagerSingletons;
|
||||||
import org.briarproject.briar.BriarCoreModule;
|
import org.briarproject.briar.BriarCoreModule;
|
||||||
|
import org.briarproject.briar.android.login.SignInReminderReceiver;
|
||||||
import org.briarproject.briar.android.reporting.BriarReportSender;
|
import org.briarproject.briar.android.reporting.BriarReportSender;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.android.DozeWatchdog;
|
import org.briarproject.briar.api.android.DozeWatchdog;
|
||||||
@@ -76,6 +78,8 @@ public interface AndroidComponent
|
|||||||
|
|
||||||
DatabaseConfig databaseConfig();
|
DatabaseConfig databaseConfig();
|
||||||
|
|
||||||
|
AccountManager accountManager();
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
Executor databaseExecutor();
|
Executor databaseExecutor();
|
||||||
|
|
||||||
@@ -150,7 +154,7 @@ public interface AndroidComponent
|
|||||||
@IoExecutor
|
@IoExecutor
|
||||||
Executor ioExecutor();
|
Executor ioExecutor();
|
||||||
|
|
||||||
void inject(BootReceiver briarService);
|
void inject(SignInReminderReceiver briarService);
|
||||||
|
|
||||||
void inject(BriarService briarService);
|
void inject(BriarService briarService);
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ class AndroidDatabaseConfig implements DatabaseConfig {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private volatile SecretKey key = null;
|
private volatile SecretKey key = null;
|
||||||
@Nullable
|
|
||||||
private volatile String nickname = null;
|
|
||||||
|
|
||||||
AndroidDatabaseConfig(File dbDir, File keyDir) {
|
AndroidDatabaseConfig(File dbDir, File keyDir) {
|
||||||
this.dbDir = dbDir;
|
this.dbDir = dbDir;
|
||||||
@@ -70,21 +68,6 @@ class AndroidDatabaseConfig implements DatabaseConfig {
|
|||||||
this.key = key;
|
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
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public SecretKey getEncryptionKey() {
|
public SecretKey getEncryptionKey() {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.content.Context;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
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.plugin.tor.TorPluginFactory;
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
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.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.android.DozeWatchdog;
|
import org.briarproject.briar.api.android.DozeWatchdog;
|
||||||
import org.briarproject.briar.api.android.ReferenceManager;
|
import org.briarproject.briar.api.android.ReferenceManager;
|
||||||
@@ -94,6 +96,13 @@ public class AppModule {
|
|||||||
return databaseConfig;
|
return databaseConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
AccountManager provideAccountManager(
|
||||||
|
AndroidAccountManagerImpl androidAccountManager) {
|
||||||
|
return androidAccountManager;
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
|
PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
|
||||||
@Scheduler ScheduledExecutorService scheduler,
|
@Scheduler ScheduledExecutorService scheduler,
|
||||||
@@ -163,6 +172,7 @@ public class AppModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
SharedPreferences provideSharedPreferences(Application app) {
|
SharedPreferences provideSharedPreferences(Application app) {
|
||||||
|
// FIXME unify this with getDefaultSharedPreferences()
|
||||||
return app.getSharedPreferences("db", MODE_PRIVATE);
|
return app.getSharedPreferences("db", MODE_PRIVATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package org.briarproject.briar.android;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.logging.LogRecord;
|
import java.util.logging.LogRecord;
|
||||||
|
|
||||||
@@ -12,4 +15,8 @@ public interface BriarApplication {
|
|||||||
Collection<LogRecord> getRecentLogRecords();
|
Collection<LogRecord> getRecentLogRecords();
|
||||||
|
|
||||||
AndroidComponent getApplicationComponent();
|
AndroidComponent getApplicationComponent();
|
||||||
|
|
||||||
|
Context getApplicationContext();
|
||||||
|
|
||||||
|
SharedPreferences getDefaultSharedPreferences();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,11 +77,12 @@ public class BriarApplicationImpl extends Application
|
|||||||
private final CachingLogHandler logHandler = new CachingLogHandler();
|
private final CachingLogHandler logHandler = new CachingLogHandler();
|
||||||
|
|
||||||
private AndroidComponent applicationComponent;
|
private AndroidComponent applicationComponent;
|
||||||
|
private volatile SharedPreferences prefs;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void attachBaseContext(Context base) {
|
protected void attachBaseContext(Context base) {
|
||||||
SharedPreferences prefs =
|
if (prefs == null)
|
||||||
PreferenceManager.getDefaultSharedPreferences(base);
|
prefs = PreferenceManager.getDefaultSharedPreferences(base);
|
||||||
// Loading the language needs to be done here.
|
// Loading the language needs to be done here.
|
||||||
Localizer.initialize(prefs);
|
Localizer.initialize(prefs);
|
||||||
super.attachBaseContext(
|
super.attachBaseContext(
|
||||||
@@ -156,4 +157,9 @@ public class BriarApplicationImpl extends Application
|
|||||||
public AndroidComponent getApplicationComponent() {
|
public AndroidComponent getApplicationComponent() {
|
||||||
return applicationComponent;
|
return applicationComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SharedPreferences getDefaultSharedPreferences() {
|
||||||
|
return prefs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ import android.os.IBinder;
|
|||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.content.ContextCompat;
|
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;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
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 android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
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.ALREADY_RUNNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_CHANNEL_ID;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_CHANNEL_ID;
|
||||||
@@ -75,7 +78,7 @@ public class BriarService extends Service {
|
|||||||
private BroadcastReceiver receiver = null;
|
private BroadcastReceiver receiver = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected DatabaseConfig databaseConfig;
|
protected AccountManager accountManager;
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject
|
@Inject
|
||||||
protected volatile LifecycleManager lifecycleManager;
|
protected volatile LifecycleManager lifecycleManager;
|
||||||
@@ -96,7 +99,8 @@ public class BriarService extends Service {
|
|||||||
stopSelf();
|
stopSelf();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (databaseConfig.getEncryptionKey() == null) {
|
AccountState accountState = accountManager.getAccountState();
|
||||||
|
if (accountState != SIGNED_IN && accountState != CREATING_ACCOUNT) {
|
||||||
LOG.info("No database key");
|
LOG.info("No database key");
|
||||||
stopSelf();
|
stopSelf();
|
||||||
return;
|
return;
|
||||||
@@ -141,7 +145,7 @@ public class BriarService extends Service {
|
|||||||
nm.cancel(REMINDER_NOTIFICATION_ID);
|
nm.cancel(REMINDER_NOTIFICATION_ID);
|
||||||
// Start the services in a background thread
|
// Start the services in a background thread
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
String nickname = databaseConfig.getLocalAuthorName();
|
String nickname = accountManager.getCreatedLocalAuthorName();
|
||||||
StartResult result = lifecycleManager.startServices(nickname);
|
StartResult result = lifecycleManager.startServices(nickname);
|
||||||
if (result == SUCCESS) {
|
if (result == SUCCESS) {
|
||||||
started = true;
|
started = true;
|
||||||
|
|||||||
@@ -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.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.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
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.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -20,27 +21,30 @@ import javax.annotation.Nullable;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.AndroidUtils.deleteAppData;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class ConfigControllerImpl implements ConfigController {
|
public class AndroidAccountManagerImpl extends AccountManagerImpl {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private final static Logger LOG =
|
||||||
Logger.getLogger(ConfigControllerImpl.class.getName());
|
Logger.getLogger(AndroidAccountManagerImpl.class.getSimpleName());
|
||||||
|
|
||||||
private static final String PREF_DB_KEY = "key";
|
private static final String PREF_DB_KEY = "key";
|
||||||
private static final String DB_KEY_FILENAME = "db.key";
|
private static final String DB_KEY_FILENAME = "db.key";
|
||||||
private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak";
|
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;
|
private final File dbKeyFile, dbKeyBackupFile;
|
||||||
protected final DatabaseConfig databaseConfig;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ConfigControllerImpl(SharedPreferences briarPrefs,
|
public AndroidAccountManagerImpl(CryptoComponent crypto,
|
||||||
DatabaseConfig databaseConfig) {
|
DatabaseConfig databaseConfig, Application app,
|
||||||
this.briarPrefs = briarPrefs;
|
SharedPreferences dbPrefs) {
|
||||||
this.databaseConfig = databaseConfig;
|
super(crypto, databaseConfig);
|
||||||
|
this.app = (BriarApplication) app;
|
||||||
|
this.dbPrefs = dbPrefs;
|
||||||
File keyDir = databaseConfig.getDatabaseKeyDirectory();
|
File keyDir = databaseConfig.getDatabaseKeyDirectory();
|
||||||
dbKeyFile = new File(keyDir, DB_KEY_FILENAME);
|
dbKeyFile = new File(keyDir, DB_KEY_FILENAME);
|
||||||
dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME);
|
dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME);
|
||||||
@@ -48,7 +52,7 @@ public class ConfigControllerImpl implements ConfigController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getEncryptedDatabaseKey() {
|
protected String getEncryptedDatabaseKey() {
|
||||||
String key = getDatabaseKeyFromPreferences();
|
String key = getDatabaseKeyFromPreferences();
|
||||||
if (key == null) key = getDatabaseKeyFromFile();
|
if (key == null) key = getDatabaseKeyFromFile();
|
||||||
else migrateDatabaseKeyToFile(key);
|
else migrateDatabaseKeyToFile(key);
|
||||||
@@ -57,7 +61,7 @@ public class ConfigControllerImpl implements ConfigController {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private String getDatabaseKeyFromPreferences() {
|
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");
|
if (key == null) LOG.info("No database key in preferences");
|
||||||
else LOG.info("Found database key in preferences");
|
else LOG.info("Found database key in preferences");
|
||||||
return key;
|
return key;
|
||||||
@@ -97,7 +101,7 @@ public class ConfigControllerImpl implements ConfigController {
|
|||||||
|
|
||||||
private void migrateDatabaseKeyToFile(String key) {
|
private void migrateDatabaseKeyToFile(String key) {
|
||||||
if (storeEncryptedDatabaseKey(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");
|
LOG.info("Database key migrated to file");
|
||||||
else LOG.warning("Database key not removed from preferences");
|
else LOG.warning("Database key not removed from preferences");
|
||||||
} else {
|
} else {
|
||||||
@@ -106,7 +110,7 @@ public class ConfigControllerImpl implements ConfigController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean storeEncryptedDatabaseKey(String hex) {
|
protected boolean storeEncryptedDatabaseKey(String hex) {
|
||||||
LOG.info("Storing database key in file");
|
LOG.info("Storing database key in file");
|
||||||
// Create the directory if necessary
|
// Create the directory if necessary
|
||||||
if (databaseConfig.getDatabaseKeyDirectory().mkdirs())
|
if (databaseConfig.getDatabaseKeyDirectory().mkdirs())
|
||||||
@@ -151,21 +155,10 @@ public class ConfigControllerImpl implements ConfigController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteAccount(Context ctx) {
|
public void deleteAccount() {
|
||||||
LOG.info("Deleting account");
|
LOG.info("Deleting account");
|
||||||
SharedPreferences defaultPrefs =
|
SharedPreferences defaultPrefs = app.getDefaultSharedPreferences();
|
||||||
PreferenceManager.getDefaultSharedPreferences(ctx);
|
deleteAppData(app.getApplicationContext(), dbPrefs, defaultPrefs);
|
||||||
AndroidUtils.deleteAppData(ctx, briarPrefs, defaultPrefs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean accountExists() {
|
|
||||||
String hex = getEncryptedDatabaseKey();
|
|
||||||
return hex != null && databaseConfig.databaseExists();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean accountSignedIn() {
|
|
||||||
return databaseConfig.getEncryptionKey() != null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.design.widget.TextInputEditText;
|
import android.support.design.widget.TextInputEditText;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Intent;
|
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.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.briar.R;
|
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.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.login.PowerView.OnCheckedChangedListener;
|
|
||||||
import org.briarproject.briar.android.util.UiUtils;
|
import org.briarproject.briar.android.util.UiUtils;
|
||||||
|
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
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.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
|
import org.briarproject.briar.android.login.StrengthMeter;
|
||||||
import org.briarproject.briar.android.util.UiUtils;
|
import org.briarproject.briar.android.util.UiUtils;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.content.Intent;
|
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.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BaseActivity;
|
import org.briarproject.briar.android.activity.BaseActivity;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
||||||
|
import org.briarproject.briar.android.login.OpenDatabaseActivity;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -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.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.briar.android.login.PasswordController;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface SetupController extends PasswordController {
|
public interface SetupController extends PasswordController {
|
||||||
@@ -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 android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
||||||
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
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.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.briar.android.controller.handler.ResultHandler;
|
import org.briarproject.briar.android.controller.handler.ResultHandler;
|
||||||
import org.briarproject.briar.android.controller.handler.UiResultHandler;
|
import org.briarproject.briar.android.controller.handler.UiResultHandler;
|
||||||
|
import org.briarproject.briar.android.login.PasswordControllerImpl;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -28,11 +27,10 @@ public class SetupControllerImpl extends PasswordControllerImpl
|
|||||||
private volatile SetupActivity setupActivity;
|
private volatile SetupActivity setupActivity;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SetupControllerImpl(SharedPreferences briarPrefs,
|
SetupControllerImpl(AccountManager accountManager,
|
||||||
DatabaseConfig databaseConfig,
|
|
||||||
@CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto,
|
@CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto,
|
||||||
PasswordStrengthEstimator strengthEstimator) {
|
PasswordStrengthEstimator strengthEstimator) {
|
||||||
super(briarPrefs, databaseConfig, cryptoExecutor, crypto,
|
super(accountManager, cryptoExecutor, crypto,
|
||||||
strengthEstimator);
|
strengthEstimator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,11 +100,7 @@ public class SetupControllerImpl extends PasswordControllerImpl
|
|||||||
if (password == null) throw new IllegalStateException();
|
if (password == null) throw new IllegalStateException();
|
||||||
cryptoExecutor.execute(() -> {
|
cryptoExecutor.execute(() -> {
|
||||||
LOG.info("Creating account");
|
LOG.info("Creating account");
|
||||||
databaseConfig.setLocalAuthorName(authorName);
|
accountManager.createAccount(authorName, password);
|
||||||
SecretKey key = crypto.generateSecretKey();
|
|
||||||
databaseConfig.setEncryptionKey(key);
|
|
||||||
String hex = encryptDatabaseKey(key, password);
|
|
||||||
storeEncryptedDatabaseKey(hex);
|
|
||||||
resultHandler.onResult(null);
|
resultHandler.onResult(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
@@ -17,7 +17,7 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
|
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 {
|
OnEditorActionListener, OnClickListener {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -30,13 +30,13 @@ import org.briarproject.briar.android.keyagreement.ContactExchangeActivity;
|
|||||||
import org.briarproject.briar.android.keyagreement.IntroFragment;
|
import org.briarproject.briar.android.keyagreement.IntroFragment;
|
||||||
import org.briarproject.briar.android.keyagreement.KeyAgreementActivity;
|
import org.briarproject.briar.android.keyagreement.KeyAgreementActivity;
|
||||||
import org.briarproject.briar.android.keyagreement.KeyAgreementFragment;
|
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.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.OpenDatabaseActivity;
|
||||||
import org.briarproject.briar.android.login.PasswordActivity;
|
import org.briarproject.briar.android.login.PasswordActivity;
|
||||||
import org.briarproject.briar.android.login.PasswordFragment;
|
import org.briarproject.briar.android.account.PasswordFragment;
|
||||||
import org.briarproject.briar.android.login.SetupActivity;
|
import org.briarproject.briar.android.account.SetupActivity;
|
||||||
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
||||||
import org.briarproject.briar.android.panic.PanicPreferencesActivity;
|
import org.briarproject.briar.android.panic.PanicPreferencesActivity;
|
||||||
import org.briarproject.briar.android.panic.PanicResponderActivity;
|
import org.briarproject.briar.android.panic.PanicResponderActivity;
|
||||||
|
|||||||
@@ -4,14 +4,12 @@ import android.app.Activity;
|
|||||||
|
|
||||||
import org.briarproject.briar.android.controller.BriarController;
|
import org.briarproject.briar.android.controller.BriarController;
|
||||||
import org.briarproject.briar.android.controller.BriarControllerImpl;
|
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.DbController;
|
||||||
import org.briarproject.briar.android.controller.DbControllerImpl;
|
import org.briarproject.briar.android.controller.DbControllerImpl;
|
||||||
import org.briarproject.briar.android.login.PasswordController;
|
import org.briarproject.briar.android.login.PasswordController;
|
||||||
import org.briarproject.briar.android.login.PasswordControllerImpl;
|
import org.briarproject.briar.android.login.PasswordControllerImpl;
|
||||||
import org.briarproject.briar.android.login.SetupController;
|
import org.briarproject.briar.android.account.SetupController;
|
||||||
import org.briarproject.briar.android.login.SetupControllerImpl;
|
import org.briarproject.briar.android.account.SetupControllerImpl;
|
||||||
import org.briarproject.briar.android.navdrawer.NavDrawerController;
|
import org.briarproject.briar.android.navdrawer.NavDrawerController;
|
||||||
import org.briarproject.briar.android.navdrawer.NavDrawerControllerImpl;
|
import org.briarproject.briar.android.navdrawer.NavDrawerControllerImpl;
|
||||||
|
|
||||||
@@ -48,13 +46,6 @@ public class ActivityModule {
|
|||||||
return setupController;
|
return setupController;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ActivityScope
|
|
||||||
@Provides
|
|
||||||
ConfigController provideConfigController(
|
|
||||||
ConfigControllerImpl configController) {
|
|
||||||
return configController;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ActivityScope
|
@ActivityScope
|
||||||
@Provides
|
@Provides
|
||||||
PasswordController providePasswordController(
|
PasswordController providePasswordController(
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public abstract class BriarActivity extends BaseActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
if (!briarController.hasEncryptionKey() && !isFinishing()) {
|
if (!briarController.signedIn() && !isFinishing()) {
|
||||||
Intent i = new Intent(this, PasswordActivity.class);
|
Intent i = new Intent(this, PasswordActivity.class);
|
||||||
startActivityForResult(i, REQUEST_PASSWORD);
|
startActivityForResult(i, REQUEST_PASSWORD);
|
||||||
} else if (SDK_INT >= 23) {
|
} else if (SDK_INT >= 23) {
|
||||||
@@ -138,7 +138,7 @@ public abstract class BriarActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void signOut(boolean removeFromRecentApps) {
|
protected void signOut(boolean removeFromRecentApps) {
|
||||||
if (briarController.hasEncryptionKey()) {
|
if (briarController.signedIn()) {
|
||||||
// Don't use UiResultHandler because we want the result even if
|
// Don't use UiResultHandler because we want the result even if
|
||||||
// this activity has been destroyed
|
// this activity has been destroyed
|
||||||
briarController.signOut(result -> runOnUiThread(
|
briarController.signOut(result -> runOnUiThread(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ public interface BriarController extends ActivityLifecycleController {
|
|||||||
|
|
||||||
void startAndBindService();
|
void startAndBindService();
|
||||||
|
|
||||||
boolean hasEncryptionKey();
|
boolean signedIn();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true via the handler when the app has dozed
|
* Returns true via the handler when the app has dozed
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import android.content.Intent;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.support.annotation.CallSuper;
|
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.DatabaseExecutor;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
@@ -21,6 +22,8 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
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.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE;
|
import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
|
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";
|
public static final String DOZE_ASK_AGAIN = "dozeAskAgain";
|
||||||
|
|
||||||
private final BriarServiceConnection serviceConnection;
|
private final BriarServiceConnection serviceConnection;
|
||||||
private final DatabaseConfig databaseConfig;
|
private final AccountManager accountManager;
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
private final Executor databaseExecutor;
|
private final Executor databaseExecutor;
|
||||||
private final SettingsManager settingsManager;
|
private final SettingsManager settingsManager;
|
||||||
@@ -44,12 +47,12 @@ public class BriarControllerImpl implements BriarController {
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
BriarControllerImpl(BriarServiceConnection serviceConnection,
|
BriarControllerImpl(BriarServiceConnection serviceConnection,
|
||||||
DatabaseConfig databaseConfig,
|
AccountManager accountManager,
|
||||||
@DatabaseExecutor Executor databaseExecutor,
|
@DatabaseExecutor Executor databaseExecutor,
|
||||||
SettingsManager settingsManager, DozeWatchdog dozeWatchdog,
|
SettingsManager settingsManager, DozeWatchdog dozeWatchdog,
|
||||||
Activity activity) {
|
Activity activity) {
|
||||||
this.serviceConnection = serviceConnection;
|
this.serviceConnection = serviceConnection;
|
||||||
this.databaseConfig = databaseConfig;
|
this.accountManager = accountManager;
|
||||||
this.databaseExecutor = databaseExecutor;
|
this.databaseExecutor = databaseExecutor;
|
||||||
this.settingsManager = settingsManager;
|
this.settingsManager = settingsManager;
|
||||||
this.dozeWatchdog = dozeWatchdog;
|
this.dozeWatchdog = dozeWatchdog;
|
||||||
@@ -59,7 +62,7 @@ public class BriarControllerImpl implements BriarController {
|
|||||||
@Override
|
@Override
|
||||||
@CallSuper
|
@CallSuper
|
||||||
public void onActivityCreate(Activity activity) {
|
public void onActivityCreate(Activity activity) {
|
||||||
if (databaseConfig.getEncryptionKey() != null) startAndBindService();
|
if (signedIn()) startAndBindService();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -84,8 +87,9 @@ public class BriarControllerImpl implements BriarController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasEncryptionKey() {
|
public boolean signedIn() {
|
||||||
return databaseConfig.getEncryptionKey() != null;
|
AccountState state = accountManager.getAccountState();
|
||||||
|
return state == CREATING_ACCOUNT || state == SIGNED_IN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -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();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -14,6 +14,7 @@ import android.widget.ProgressBar;
|
|||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.Localizer;
|
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.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BaseActivity;
|
import org.briarproject.briar.android.activity.BaseActivity;
|
||||||
import org.briarproject.briar.android.controller.BriarController;
|
import org.briarproject.briar.android.controller.BriarController;
|
||||||
@@ -85,7 +86,7 @@ public class PasswordActivity extends BaseActivity {
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
// If the user has already signed in, clean up this instance
|
// If the user has already signed in, clean up this instance
|
||||||
if (briarController.hasEncryptionKey()) {
|
if (briarController.signedIn()) {
|
||||||
setResult(RESULT_OK);
|
setResult(RESULT_OK);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
@@ -105,7 +106,7 @@ public class PasswordActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void deleteAccount() {
|
private void deleteAccount() {
|
||||||
passwordController.deleteAccount(this);
|
passwordController.deleteAccount();
|
||||||
Localizer.reinitialize();
|
Localizer.reinitialize();
|
||||||
UiUtils.setTheme(this, getString(R.string.pref_theme_light_value));
|
UiUtils.setTheme(this, getString(R.string.pref_theme_light_value));
|
||||||
setResult(RESULT_CANCELED);
|
setResult(RESULT_CANCELED);
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android.login;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.briar.android.controller.ConfigController;
|
|
||||||
import org.briarproject.briar.android.controller.handler.ResultHandler;
|
import org.briarproject.briar.android.controller.handler.ResultHandler;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface PasswordController extends ConfigController {
|
public interface PasswordController {
|
||||||
|
|
||||||
|
boolean accountExists();
|
||||||
|
|
||||||
float estimatePasswordStrength(String password);
|
float estimatePasswordStrength(String password);
|
||||||
|
|
||||||
@@ -15,4 +16,6 @@ public interface PasswordController extends ConfigController {
|
|||||||
void changePassword(String password, String newPassword,
|
void changePassword(String password, String newPassword,
|
||||||
ResultHandler<Boolean> resultHandler);
|
ResultHandler<Boolean> resultHandler);
|
||||||
|
|
||||||
|
void deleteAccount();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,41 @@
|
|||||||
package org.briarproject.briar.android.login;
|
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.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
import org.briarproject.bramble.api.crypto.CryptoExecutor;
|
||||||
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
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.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 org.briarproject.briar.android.controller.handler.ResultHandler;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.api.account.AccountState.NO_ACCOUNT;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class PasswordControllerImpl extends ConfigControllerImpl
|
public class PasswordControllerImpl implements PasswordController {
|
||||||
implements PasswordController {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(PasswordControllerImpl.class.getName());
|
|
||||||
|
|
||||||
|
protected final AccountManager accountManager;
|
||||||
protected final Executor cryptoExecutor;
|
protected final Executor cryptoExecutor;
|
||||||
protected final CryptoComponent crypto;
|
protected final CryptoComponent crypto;
|
||||||
private final PasswordStrengthEstimator strengthEstimator;
|
private final PasswordStrengthEstimator strengthEstimator;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
PasswordControllerImpl(SharedPreferences briarPrefs,
|
public PasswordControllerImpl(AccountManager accountManager,
|
||||||
DatabaseConfig databaseConfig,
|
|
||||||
@CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto,
|
@CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto,
|
||||||
PasswordStrengthEstimator strengthEstimator) {
|
PasswordStrengthEstimator strengthEstimator) {
|
||||||
super(briarPrefs, databaseConfig);
|
this.accountManager = accountManager;
|
||||||
this.cryptoExecutor = cryptoExecutor;
|
this.cryptoExecutor = cryptoExecutor;
|
||||||
this.crypto = crypto;
|
this.crypto = crypto;
|
||||||
this.strengthEstimator = strengthEstimator;
|
this.strengthEstimator = strengthEstimator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accountExists() {
|
||||||
|
return accountManager.getAccountState() != NO_ACCOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float estimatePasswordStrength(String password) {
|
public float estimatePasswordStrength(String password) {
|
||||||
return strengthEstimator.estimateStrength(password);
|
return strengthEstimator.estimateStrength(password);
|
||||||
@@ -50,46 +44,25 @@ public class PasswordControllerImpl extends ConfigControllerImpl
|
|||||||
@Override
|
@Override
|
||||||
public void validatePassword(String password,
|
public void validatePassword(String password,
|
||||||
ResultHandler<Boolean> resultHandler) {
|
ResultHandler<Boolean> resultHandler) {
|
||||||
byte[] encrypted = getEncryptedKey();
|
|
||||||
cryptoExecutor.execute(() -> {
|
cryptoExecutor.execute(() -> {
|
||||||
byte[] key = crypto.decryptWithPassword(encrypted, password);
|
boolean result = accountManager.validatePassword(password);
|
||||||
if (key == null) {
|
resultHandler.onResult(result);
|
||||||
resultHandler.onResult(false);
|
|
||||||
} else {
|
|
||||||
databaseConfig.setEncryptionKey(new SecretKey(key));
|
|
||||||
resultHandler.onResult(true);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void changePassword(String password, String newPassword,
|
public void changePassword(String password, String newPassword,
|
||||||
ResultHandler<Boolean> resultHandler) {
|
ResultHandler<Boolean> resultHandler) {
|
||||||
byte[] encrypted = getEncryptedKey();
|
|
||||||
cryptoExecutor.execute(() -> {
|
cryptoExecutor.execute(() -> {
|
||||||
byte[] key = crypto.decryptWithPassword(encrypted, password);
|
boolean result =
|
||||||
if (key == null) {
|
accountManager.changePassword(password, newPassword);
|
||||||
resultHandler.onResult(false);
|
resultHandler.onResult(result);
|
||||||
} else {
|
|
||||||
String hex =
|
|
||||||
encryptDatabaseKey(new SecretKey(key), newPassword);
|
|
||||||
resultHandler.onResult(storeEncryptedDatabaseKey(hex));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] getEncryptedKey() {
|
@Override
|
||||||
String hex = getEncryptedDatabaseKey();
|
public void deleteAccount() {
|
||||||
if (hex == null)
|
accountManager.deleteAccount();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android;
|
package org.briarproject.briar.android.login;
|
||||||
|
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
@@ -6,45 +6,57 @@ import android.app.PendingIntent;
|
|||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.content.ContextCompat;
|
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.R;
|
||||||
|
import org.briarproject.briar.android.AndroidComponent;
|
||||||
|
import org.briarproject.briar.android.BriarApplication;
|
||||||
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
||||||
|
import org.briarproject.briar.android.settings.SettingsActivity;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
import static android.app.NotificationManager.IMPORTANCE_LOW;
|
||||||
import static android.content.Context.NOTIFICATION_SERVICE;
|
import static android.content.Context.NOTIFICATION_SERVICE;
|
||||||
import static android.content.Intent.ACTION_BOOT_COMPLETED;
|
import static android.content.Intent.ACTION_BOOT_COMPLETED;
|
||||||
|
import static android.content.Intent.ACTION_MY_PACKAGE_REPLACED;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.support.v4.app.NotificationCompat.PRIORITY_LOW;
|
import static android.support.v4.app.NotificationCompat.PRIORITY_LOW;
|
||||||
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
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.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;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.REMINDER_CHANNEL_ID;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.REMINDER_CHANNEL_ID;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.REMINDER_NOTIFICATION_ID;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.REMINDER_NOTIFICATION_ID;
|
||||||
|
|
||||||
public class BootReceiver extends BroadcastReceiver {
|
public class SignInReminderReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
DatabaseConfig databaseConfig;
|
AccountManager accountManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context ctx, Intent intent) {
|
public void onReceive(Context ctx, Intent intent) {
|
||||||
if (!FEATURE_FLAG_SIGN_IN_REMINDER) return;
|
if (!FEATURE_FLAG_SIGN_IN_REMINDER) return;
|
||||||
|
|
||||||
AndroidComponent applicationComponent =
|
BriarApplication app = (BriarApplication) ctx.getApplicationContext();
|
||||||
((BriarApplication) ctx.getApplicationContext())
|
AndroidComponent applicationComponent = app.getApplicationComponent();
|
||||||
.getApplicationComponent();
|
|
||||||
applicationComponent.inject(this);
|
applicationComponent.inject(this);
|
||||||
|
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
if (action != null && action.equals(ACTION_BOOT_COMPLETED)) {
|
if (action == null) return;
|
||||||
if (databaseConfig.databaseExists()) {
|
if (action.equals(ACTION_BOOT_COMPLETED) ||
|
||||||
showSignInNotification(ctx);
|
action.equals(ACTION_MY_PACKAGE_REPLACED)) {
|
||||||
|
if (accountManager.getAccountState() != NO_ACCOUNT) {
|
||||||
|
SharedPreferences prefs = app.getDefaultSharedPreferences();
|
||||||
|
if (prefs.getBoolean(NOTIFY_SIGN_IN, true)) {
|
||||||
|
showSignInNotification(ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,6 +85,14 @@ public class BootReceiver extends BroadcastReceiver {
|
|||||||
b.setWhen(0); // Don't show the time
|
b.setWhen(0); // Don't show the time
|
||||||
b.setPriority(PRIORITY_LOW);
|
b.setPriority(PRIORITY_LOW);
|
||||||
|
|
||||||
|
// Add a 'Do not show sign-in reminder' action
|
||||||
|
String actionTitle =
|
||||||
|
ctx.getString(R.string.reminder_notification_do_not_show_again);
|
||||||
|
Intent i1 = new Intent(ctx, SettingsActivity.class);
|
||||||
|
i1.setAction(NO_NOTIFY_SIGN_IN);
|
||||||
|
PendingIntent actionIntent = PendingIntent.getActivity(ctx, 0, i1, 0);
|
||||||
|
b.addAction(0, actionTitle, actionIntent);
|
||||||
|
|
||||||
Intent i = new Intent(ctx, NavDrawerActivity.class);
|
Intent i = new Intent(ctx, NavDrawerActivity.class);
|
||||||
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
|
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
b.setContentIntent(PendingIntent.getActivity(ctx, 0, i, 0));
|
b.setContentIntent(PendingIntent.getActivity(ctx, 0, i, 0));
|
||||||
@@ -7,10 +7,10 @@ import android.os.Build;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.preference.PreferenceManager;
|
import android.support.v7.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
import org.briarproject.briar.android.controller.ConfigController;
|
|
||||||
import org.iilab.IilabEngineeringRSA2048Pin;
|
import org.iilab.IilabEngineeringRSA2048Pin;
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -33,7 +33,7 @@ public class PanicResponderActivity extends BriarActivity {
|
|||||||
Logger.getLogger(PanicResponderActivity.class.getName());
|
Logger.getLogger(PanicResponderActivity.class.getName());
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected ConfigController configController;
|
protected AccountManager accountManager;
|
||||||
@Inject
|
@Inject
|
||||||
protected AndroidExecutor androidExecutor;
|
protected AndroidExecutor androidExecutor;
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ public class PanicResponderActivity extends BriarActivity {
|
|||||||
|
|
||||||
private void deleteAllData() {
|
private void deleteAllData() {
|
||||||
androidExecutor.runOnBackgroundThread(() -> {
|
androidExecutor.runOnBackgroundThread(() -> {
|
||||||
configController.deleteAccount(PanicResponderActivity.this);
|
accountManager.deleteAccount();
|
||||||
// TODO somehow delete/shred the database more thoroughly
|
// TODO somehow delete/shred the database more thoroughly
|
||||||
PanicResponder.deleteAllAppData(PanicResponderActivity.this);
|
PanicResponder.deleteAllAppData(PanicResponderActivity.this);
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,43 @@
|
|||||||
package org.briarproject.briar.android.settings;
|
package org.briarproject.briar.android.settings;
|
||||||
|
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.BriarApplication;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
|
|
||||||
|
import static org.briarproject.briar.android.settings.SettingsFragment.NOTIFY_SIGN_IN;
|
||||||
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.REMINDER_NOTIFICATION_ID;
|
||||||
|
|
||||||
public class SettingsActivity extends BriarActivity {
|
public class SettingsActivity extends BriarActivity {
|
||||||
|
|
||||||
|
public static final String NO_NOTIFY_SIGN_IN = "noNotifySignIn";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle bundle) {
|
public void onCreate(Bundle bundle) {
|
||||||
super.onCreate(bundle);
|
super.onCreate(bundle);
|
||||||
|
|
||||||
|
// Maybe turn off sign-in reminder
|
||||||
|
Intent intent = getIntent();
|
||||||
|
if (intent != null && NO_NOTIFY_SIGN_IN.equals(intent.getAction())) {
|
||||||
|
// Turn it off
|
||||||
|
BriarApplication app = (BriarApplication) getApplication();
|
||||||
|
SharedPreferences prefs = app.getDefaultSharedPreferences();
|
||||||
|
prefs.edit().putBoolean(NOTIFY_SIGN_IN, false).apply();
|
||||||
|
// Remove sign-in reminder notification
|
||||||
|
NotificationManager nm = (NotificationManager)
|
||||||
|
getSystemService(NOTIFICATION_SERVICE);
|
||||||
|
if (nm != null) nm.cancel(REMINDER_NOTIFICATION_ID);
|
||||||
|
// Finish this activity again
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
ActionBar actionBar = getSupportActionBar();
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
actionBar.setHomeButtonEnabled(true);
|
actionBar.setHomeButtonEnabled(true);
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ import static org.briarproject.bramble.util.LogUtils.logDuration;
|
|||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
import static org.briarproject.briar.android.TestingConstants.FEATURE_FLAG_DARK_THEME;
|
import static org.briarproject.briar.android.TestingConstants.FEATURE_FLAG_DARK_THEME;
|
||||||
|
import static org.briarproject.briar.android.TestingConstants.FEATURE_FLAG_SIGN_IN_REMINDER;
|
||||||
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
||||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_RINGTONE;
|
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_RINGTONE;
|
||||||
import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_SIGN_OUT;
|
import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_SIGN_OUT;
|
||||||
@@ -97,6 +98,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
public static final String BT_NAMESPACE = BluetoothConstants.ID.getString();
|
public static final String BT_NAMESPACE = BluetoothConstants.ID.getString();
|
||||||
public static final String TOR_NAMESPACE = TorConstants.ID.getString();
|
public static final String TOR_NAMESPACE = TorConstants.ID.getString();
|
||||||
public static final String LANGUAGE = "pref_key_language";
|
public static final String LANGUAGE = "pref_key_language";
|
||||||
|
public static final String NOTIFY_SIGN_IN = "pref_key_notify_sign_in";
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(SettingsFragment.class.getName());
|
Logger.getLogger(SettingsFragment.class.getName());
|
||||||
@@ -143,6 +145,8 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
(ListPreference) findPreference("pref_key_theme");
|
(ListPreference) findPreference("pref_key_theme");
|
||||||
enableBluetooth = (ListPreference) findPreference("pref_key_bluetooth");
|
enableBluetooth = (ListPreference) findPreference("pref_key_bluetooth");
|
||||||
torNetwork = (ListPreference) findPreference("pref_key_tor_network");
|
torNetwork = (ListPreference) findPreference("pref_key_tor_network");
|
||||||
|
CheckBoxPreference notifySignIn =
|
||||||
|
(CheckBoxPreference) findPreference(NOTIFY_SIGN_IN);
|
||||||
notifyPrivateMessages = (CheckBoxPreference) findPreference(
|
notifyPrivateMessages = (CheckBoxPreference) findPreference(
|
||||||
"pref_key_notify_private_messages");
|
"pref_key_notify_private_messages");
|
||||||
notifyGroupMessages = (CheckBoxPreference) findPreference(
|
notifyGroupMessages = (CheckBoxPreference) findPreference(
|
||||||
@@ -199,6 +203,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
theme.setVisible(FEATURE_FLAG_DARK_THEME);
|
theme.setVisible(FEATURE_FLAG_DARK_THEME);
|
||||||
|
notifySignIn.setVisible(FEATURE_FLAG_SIGN_IN_REMINDER);
|
||||||
|
|
||||||
findPreference("pref_key_explode").setVisible(false);
|
findPreference("pref_key_explode").setVisible(false);
|
||||||
findPreference("pref_key_test_data").setVisible(false);
|
findPreference("pref_key_test_data").setVisible(false);
|
||||||
@@ -346,7 +351,9 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setSettingsEnabled(boolean enabled) {
|
private void setSettingsEnabled(boolean enabled) {
|
||||||
// theme not needed here, because handled by SharedPreferences
|
// preferences not needed here, because handled by SharedPreferences:
|
||||||
|
// - pref_key_theme
|
||||||
|
// - pref_key_notify_sign_in
|
||||||
enableBluetooth.setEnabled(enabled);
|
enableBluetooth.setEnabled(enabled);
|
||||||
torNetwork.setEnabled(enabled);
|
torNetwork.setEnabled(enabled);
|
||||||
notifyPrivateMessages.setEnabled(enabled);
|
notifyPrivateMessages.setEnabled(enabled);
|
||||||
|
|||||||
@@ -7,18 +7,20 @@ import android.os.Handler;
|
|||||||
import android.support.v7.preference.PreferenceManager;
|
import android.support.v7.preference.PreferenceManager;
|
||||||
import android.transition.Fade;
|
import android.transition.Fade;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
import org.briarproject.briar.R;
|
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.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BaseActivity;
|
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.OpenDatabaseActivity;
|
||||||
import org.briarproject.briar.android.login.SetupActivity;
|
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
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;
|
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
|
||||||
|
|
||||||
public class SplashScreenActivity extends BaseActivity {
|
public class SplashScreenActivity extends BaseActivity {
|
||||||
@@ -27,7 +29,7 @@ public class SplashScreenActivity extends BaseActivity {
|
|||||||
Logger.getLogger(SplashScreenActivity.class.getName());
|
Logger.getLogger(SplashScreenActivity.class.getName());
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected ConfigController configController;
|
AccountManager accountManager;
|
||||||
@Inject
|
@Inject
|
||||||
protected AndroidExecutor androidExecutor;
|
protected AndroidExecutor androidExecutor;
|
||||||
|
|
||||||
@@ -43,7 +45,7 @@ public class SplashScreenActivity extends BaseActivity {
|
|||||||
|
|
||||||
setContentView(R.layout.splash);
|
setContentView(R.layout.splash);
|
||||||
|
|
||||||
if (configController.accountSignedIn()) {
|
if (accountManager.getAccountState() == SIGNED_IN) {
|
||||||
startActivity(new Intent(this, OpenDatabaseActivity.class));
|
startActivity(new Intent(this, OpenDatabaseActivity.class));
|
||||||
finish();
|
finish();
|
||||||
} else {
|
} else {
|
||||||
@@ -64,12 +66,12 @@ public class SplashScreenActivity extends BaseActivity {
|
|||||||
LOG.info("Expired");
|
LOG.info("Expired");
|
||||||
startActivity(new Intent(this, ExpiredActivity.class));
|
startActivity(new Intent(this, ExpiredActivity.class));
|
||||||
} else {
|
} else {
|
||||||
if (configController.accountExists()) {
|
if (accountManager.getAccountState() != NO_ACCOUNT) {
|
||||||
LOG.info("Account exists");
|
LOG.info("Account exists");
|
||||||
startActivity(new Intent(this, OpenDatabaseActivity.class));
|
startActivity(new Intent(this, OpenDatabaseActivity.class));
|
||||||
} else {
|
} else {
|
||||||
LOG.info("Account does not exist");
|
LOG.info("Account does not exist");
|
||||||
configController.deleteAccount(this);
|
accountManager.deleteAccount();
|
||||||
startActivity(new Intent(this, SetupActivity.class));
|
startActivity(new Intent(this, SetupActivity.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
<string name="reminder_notification_title">Signed out of Briar</string>
|
<string name="reminder_notification_title">Signed out of Briar</string>
|
||||||
<string name="reminder_notification_text">Tap to sign back in or swipe to dismiss.</string>
|
<string name="reminder_notification_text">Tap to sign back in or swipe to dismiss.</string>
|
||||||
<string name="reminder_notification_channel_title">Briar Sign-in Reminder</string>
|
<string name="reminder_notification_channel_title">Briar Sign-in Reminder</string>
|
||||||
|
<string name="reminder_notification_do_not_show_again">Don\'t show again</string>
|
||||||
<string name="ongoing_notification_title">Signed into Briar</string>
|
<string name="ongoing_notification_title">Signed into Briar</string>
|
||||||
<string name="ongoing_notification_text">Touch to open Briar.</string>
|
<string name="ongoing_notification_text">Touch to open Briar.</string>
|
||||||
<plurals name="private_message_notification_text">
|
<plurals name="private_message_notification_text">
|
||||||
@@ -373,6 +374,8 @@
|
|||||||
|
|
||||||
<!-- Settings Notifications -->
|
<!-- Settings Notifications -->
|
||||||
<string name="notification_settings_title">Notifications</string>
|
<string name="notification_settings_title">Notifications</string>
|
||||||
|
<string name="notify_sign_in_title">Remind me to sign in</string>
|
||||||
|
<string name="notify_sign_in_summary">Show a reminder when the phone starts or the app got updated</string>
|
||||||
<string name="notify_private_messages_setting_title">Private messages</string>
|
<string name="notify_private_messages_setting_title">Private messages</string>
|
||||||
<string name="notify_private_messages_setting_summary">Show alerts for private messages</string>
|
<string name="notify_private_messages_setting_summary">Show alerts for private messages</string>
|
||||||
<string name="notify_private_messages_setting_summary_26">Configure alerts for private messages</string>
|
<string name="notify_private_messages_setting_summary_26">Configure alerts for private messages</string>
|
||||||
|
|||||||
@@ -81,6 +81,12 @@
|
|||||||
android:layout="@layout/preferences_category"
|
android:layout="@layout/preferences_category"
|
||||||
android:title="@string/notification_settings_title">
|
android:title="@string/notification_settings_title">
|
||||||
|
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:defaultValue="true"
|
||||||
|
android:key="pref_key_notify_sign_in"
|
||||||
|
android:summary="@string/notify_sign_in_summary"
|
||||||
|
android:title="@string/notify_sign_in_title"/>
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:key="pref_key_notify_private_messages"
|
android:key="pref_key_notify_private_messages"
|
||||||
|
|||||||
@@ -23,13 +23,14 @@ public class TestBriarApplication extends Application
|
|||||||
Logger.getLogger(TestBriarApplication.class.getName());
|
Logger.getLogger(TestBriarApplication.class.getName());
|
||||||
|
|
||||||
private AndroidComponent applicationComponent;
|
private AndroidComponent applicationComponent;
|
||||||
|
private SharedPreferences prefs;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
LOG.info("Created");
|
LOG.info("Created");
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
Localizer.initialize(prefs);
|
Localizer.initialize(prefs);
|
||||||
applicationComponent = DaggerAndroidComponent.builder()
|
applicationComponent = DaggerAndroidComponent.builder()
|
||||||
.appModule(new AppModule(this))
|
.appModule(new AppModule(this))
|
||||||
@@ -51,4 +52,9 @@ public class TestBriarApplication extends Application
|
|||||||
public AndroidComponent getApplicationComponent() {
|
public AndroidComponent getApplicationComponent() {
|
||||||
return applicationComponent;
|
return applicationComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SharedPreferences getDefaultSharedPreferences() {
|
||||||
|
return prefs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
import android.support.design.widget.TextInputLayout;
|
import android.support.design.widget.TextInputLayout;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -7,6 +7,7 @@ import android.widget.EditText;
|
|||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.TestBriarApplication;
|
import org.briarproject.briar.android.TestBriarApplication;
|
||||||
|
import org.briarproject.briar.android.login.StrengthMeter;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
import android.support.design.widget.TextInputLayout;
|
import android.support.design.widget.TextInputLayout;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.TestBriarApplication;
|
import org.briarproject.briar.android.TestBriarApplication;
|
||||||
|
import org.briarproject.briar.android.account.SetupActivity;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -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 android.content.pm.ApplicationInfo;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
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.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||||
@@ -18,22 +17,17 @@ import java.io.File;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import static junit.framework.Assert.assertEquals;
|
|
||||||
import static junit.framework.Assert.assertFalse;
|
import static junit.framework.Assert.assertFalse;
|
||||||
import static junit.framework.Assert.assertTrue;
|
import static junit.framework.Assert.assertTrue;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
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.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.test.TestUtils.getTestDirectory;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
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 {
|
public class SetupControllerImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
private final SharedPreferences briarPrefs =
|
private final AccountManager accountManager =
|
||||||
context.mock(SharedPreferences.class);
|
context.mock(AccountManager.class);
|
||||||
private final DatabaseConfig databaseConfig =
|
private final DatabaseConfig databaseConfig =
|
||||||
context.mock(DatabaseConfig.class);
|
context.mock(DatabaseConfig.class);
|
||||||
private final CryptoComponent crypto = context.mock(CryptoComponent.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 authorName = getRandomString(MAX_AUTHOR_NAME_LENGTH);
|
||||||
private final String password = "some.strong.pass";
|
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 testDir = getTestDirectory();
|
||||||
private final File keyDir = new File(testDir, "key");
|
private final File keyDir = new File(testDir, "key");
|
||||||
private final File keyFile = new File(keyDir, "db.key");
|
private final File keyFile = new File(keyDir, "db.key");
|
||||||
@@ -74,25 +66,15 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(authorName));
|
will(returnValue(authorName));
|
||||||
oneOf(setupActivity).getPassword();
|
oneOf(setupActivity).getPassword();
|
||||||
will(returnValue(password));
|
will(returnValue(password));
|
||||||
// Generate a database key
|
oneOf(accountManager).createAccount(authorName, password);
|
||||||
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));
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
assertFalse(keyFile.exists());
|
||||||
assertFalse(keyBackupFile.exists());
|
assertFalse(keyBackupFile.exists());
|
||||||
|
|
||||||
SetupControllerImpl s = new SetupControllerImpl(briarPrefs,
|
SetupControllerImpl s =
|
||||||
databaseConfig, cryptoExecutor, crypto, estimator);
|
new SetupControllerImpl(accountManager, cryptoExecutor, crypto,
|
||||||
|
estimator);
|
||||||
s.setSetupActivity(setupActivity);
|
s.setSetupActivity(setupActivity);
|
||||||
|
|
||||||
AtomicBoolean called = new AtomicBoolean(false);
|
AtomicBoolean called = new AtomicBoolean(false);
|
||||||
@@ -100,11 +82,6 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
|
|||||||
s.setPassword(password);
|
s.setPassword(password);
|
||||||
s.createAccount(result -> called.set(true));
|
s.createAccount(result -> called.set(true));
|
||||||
assertTrue(called.get());
|
assertTrue(called.get());
|
||||||
|
|
||||||
assertTrue(keyFile.exists());
|
|
||||||
assertTrue(keyBackupFile.exists());
|
|
||||||
assertEquals(toHexString(encryptedKey), loadDatabaseKey(keyFile));
|
|
||||||
assertEquals(toHexString(encryptedKey), loadDatabaseKey(keyBackupFile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,7 +45,7 @@ public class TestForumActivity extends ForumActivity {
|
|||||||
protected BriarController provideBriarController(
|
protected BriarController provideBriarController(
|
||||||
BriarControllerImpl briarController) {
|
BriarControllerImpl briarController) {
|
||||||
BriarController c = Mockito.mock(BriarController.class);
|
BriarController c = Mockito.mock(BriarController.class);
|
||||||
Mockito.when(c.hasEncryptionKey()).thenReturn(true);
|
Mockito.when(c.signedIn()).thenReturn(true);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +1,23 @@
|
|||||||
package org.briarproject.briar.android.login;
|
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.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
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.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import static junit.framework.Assert.assertEquals;
|
|
||||||
import static junit.framework.Assert.assertFalse;
|
import static junit.framework.Assert.assertFalse;
|
||||||
import static junit.framework.Assert.assertTrue;
|
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 {
|
public class PasswordControllerImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
private final SharedPreferences briarPrefs =
|
private final AccountManager accountManager =
|
||||||
context.mock(SharedPreferences.class);
|
context.mock(AccountManager.class);
|
||||||
private final DatabaseConfig databaseConfig =
|
|
||||||
context.mock(DatabaseConfig.class);
|
|
||||||
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
private final PasswordStrengthEstimator estimator =
|
private final PasswordStrengthEstimator estimator =
|
||||||
context.mock(PasswordStrengthEstimator.class);
|
context.mock(PasswordStrengthEstimator.class);
|
||||||
@@ -40,85 +26,37 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
private final String oldPassword = "some.old.pass";
|
private final String oldPassword = "some.old.pass";
|
||||||
private final String newPassword = "some.new.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
|
@Test
|
||||||
public void testChangePasswordReturnsTrue() throws Exception {
|
public void testChangePasswordReturnsTrue() {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Look up the encrypted DB key
|
oneOf(accountManager).changePassword(oldPassword, newPassword);
|
||||||
oneOf(briarPrefs).getString("key", null);
|
will(returnValue(true));
|
||||||
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));
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
PasswordControllerImpl p =
|
||||||
assertFalse(keyBackupFile.exists());
|
new PasswordControllerImpl(accountManager, cryptoExecutor,
|
||||||
|
crypto, estimator);
|
||||||
storeDatabaseKey(keyFile, toHexString(oldEncryptedKey));
|
|
||||||
storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey));
|
|
||||||
|
|
||||||
PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
|
|
||||||
databaseConfig, cryptoExecutor, crypto, estimator);
|
|
||||||
|
|
||||||
AtomicBoolean capturedResult = new AtomicBoolean(false);
|
AtomicBoolean capturedResult = new AtomicBoolean(false);
|
||||||
p.changePassword(oldPassword, newPassword, capturedResult::set);
|
p.changePassword(oldPassword, newPassword, capturedResult::set);
|
||||||
assertTrue(capturedResult.get());
|
assertTrue(capturedResult.get());
|
||||||
|
|
||||||
assertTrue(keyFile.exists());
|
|
||||||
assertTrue(keyBackupFile.exists());
|
|
||||||
assertEquals(toHexString(newEncryptedKey), loadDatabaseKey(keyFile));
|
|
||||||
assertEquals(toHexString(newEncryptedKey),
|
|
||||||
loadDatabaseKey(keyBackupFile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChangePasswordReturnsFalseIfOldPasswordIsWrong()
|
public void testChangePasswordReturnsFalseIfOldPasswordIsWrong() {
|
||||||
throws Exception {
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Look up the encrypted DB key
|
oneOf(accountManager).changePassword(oldPassword, newPassword);
|
||||||
oneOf(briarPrefs).getString("key", null);
|
will(returnValue(false));
|
||||||
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));
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
PasswordControllerImpl p =
|
||||||
assertFalse(keyBackupFile.exists());
|
new PasswordControllerImpl(accountManager, cryptoExecutor,
|
||||||
|
crypto, estimator);
|
||||||
storeDatabaseKey(keyFile, toHexString(oldEncryptedKey));
|
|
||||||
storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey));
|
|
||||||
|
|
||||||
PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
|
|
||||||
databaseConfig, cryptoExecutor, crypto, estimator);
|
|
||||||
|
|
||||||
AtomicBoolean capturedResult = new AtomicBoolean(true);
|
AtomicBoolean capturedResult = new AtomicBoolean(true);
|
||||||
p.changePassword(oldPassword, newPassword, capturedResult::set);
|
p.changePassword(oldPassword, newPassword, capturedResult::set);
|
||||||
assertFalse(capturedResult.get());
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user