phase 2: helpers and app bus

This commit is contained in:
Ernir Erlingsson
2016-04-01 14:34:41 +02:00
parent 7b552bde1e
commit a9de12520d
21 changed files with 435 additions and 171 deletions

View File

@@ -4,15 +4,16 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment;
import org.briarproject.android.contact.ContactListFragment; import org.briarproject.android.contact.ContactListFragment;
import org.briarproject.android.forum.ForumListFragment; import org.briarproject.android.forum.ForumListFragment;
import org.briarproject.android.fragment.BaseFragment; import org.briarproject.android.fragment.BaseFragment;
import org.briarproject.android.sdk.BriarHelper; import org.briarproject.android.helper.PasswordHelper;
import org.briarproject.android.sdk.BriarHelperImp; import org.briarproject.android.helper.PasswordHelperImp;
import org.briarproject.android.helper.SetupHelper;
import java.util.logging.Logger; import org.briarproject.android.helper.SetupHelperImp;
import org.briarproject.android.helper.ConfigHelper;
import org.briarproject.android.helper.ConfigHelperImp;
import javax.inject.Named; import javax.inject.Named;
@@ -36,13 +37,14 @@ public class ActivityModule {
@ActivityScope @ActivityScope
@Provides @Provides
BriarHelper provideBriarHelper(BriarHelperImp briarHelperImp) { SetupHelper provideSetupHelper(SetupHelperImp setupHelperImp) {
return briarHelperImp; return setupHelperImp;
} }
@ActivityScope @ActivityScope
Logger provideLogger(Activity activity) { @Provides
return Logger.getLogger(activity.getClass().getName()); ConfigHelper provideConfigHelper(ConfigHelperImp configHelperImp) {
return configHelperImp;
} }
@ActivityScope @ActivityScope
@@ -51,6 +53,11 @@ public class ActivityModule {
return activity.getSharedPreferences("db", Context.MODE_PRIVATE); return activity.getSharedPreferences("db", Context.MODE_PRIVATE);
} }
@ActivityScope
@Provides
PasswordHelper providePasswordHelper(PasswordHelperImp passwordHelperImp) {
return passwordHelperImp;
}
@Provides @Provides
@Named("ForumListFragment") @Named("ForumListFragment")

View File

@@ -6,6 +6,7 @@ import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.api.ReferenceManager; import org.briarproject.android.api.ReferenceManager;
import org.briarproject.android.contact.ContactListFragment; import org.briarproject.android.contact.ContactListFragment;
import org.briarproject.android.contact.ConversationActivity; import org.briarproject.android.contact.ConversationActivity;
import org.briarproject.android.event.AppBus;
import org.briarproject.android.forum.AvailableForumsActivity; import org.briarproject.android.forum.AvailableForumsActivity;
import org.briarproject.android.forum.ContactSelectorFragment; import org.briarproject.android.forum.ContactSelectorFragment;
import org.briarproject.android.forum.CreateForumActivity; import org.briarproject.android.forum.CreateForumActivity;
@@ -50,6 +51,7 @@ import org.briarproject.system.AndroidSystemModule;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import dagger.Component; import dagger.Component;
@@ -74,6 +76,7 @@ public interface AndroidComponent extends CoreEagerSingletons {
IdentityManager identityManager(); IdentityManager identityManager();
PluginManager pluginManager(); PluginManager pluginManager();
EventBus eventBus(); EventBus eventBus();
AppBus appEventBus();
InvitationTaskFactory invitationTaskFactory(); InvitationTaskFactory invitationTaskFactory();
AndroidNotificationManager androidNotificationManager(); AndroidNotificationManager androidNotificationManager();
ConnectionRegistry connectionRegistry(); ConnectionRegistry connectionRegistry();

View File

@@ -1,29 +1,30 @@
package org.briarproject.android; package org.briarproject.android;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.support.annotation.CallSuper;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import org.briarproject.android.event.AppBus;
import org.briarproject.android.event.ErrorEvent;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventListener;
import javax.inject.Inject; import javax.inject.Inject;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE; import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT; import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS; import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS;
public abstract class BaseActivity extends AppCompatActivity { public abstract class BaseActivity extends AppCompatActivity implements
EventListener {
public final static String PREFS_NAME = "db";
public final static String PREF_DB_KEY = "key";
public final static String PREF_SEEN_WELCOME_MESSAGE = "welcome_message";
protected ActivityComponent activityComponent; protected ActivityComponent activityComponent;
// TODO Shared prefs @Inject
protected AppBus appBus;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@@ -42,28 +43,28 @@ public abstract class BaseActivity extends AppCompatActivity {
injectActivity(activityComponent); injectActivity(activityComponent);
} }
@Override
protected void onResume() {
super.onResume();
appBus.addListener(this);
}
@Override
protected void onPause() {
appBus.removeListener(this);
super.onPause();
}
@Override
@CallSuper
public void eventOccurred(Event e) {
if (e instanceof ErrorEvent) {
finish();
}
}
public abstract void injectActivity(ActivityComponent component); public abstract void injectActivity(ActivityComponent component);
private SharedPreferences getSharedPrefs() {
return getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
}
protected String getEncryptedDatabaseKey() {
return getSharedPrefs().getString(PREF_DB_KEY, null);
}
protected void storeEncryptedDatabaseKey(final String hex) {
SharedPreferences.Editor editor = getSharedPrefs().edit();
editor.putString(PREF_DB_KEY, hex);
editor.apply();
}
protected void clearSharedPrefs() {
SharedPreferences.Editor editor = getSharedPrefs().edit();
editor.clear();
editor.apply();
}
protected void showSoftKeyboard(View view) { protected void showSoftKeyboard(View view) {
Object o = getSystemService(INPUT_METHOD_SERVICE); Object o = getSystemService(INPUT_METHOD_SERVICE);
((InputMethodManager) o).showSoftInput(view, SHOW_IMPLICIT); ((InputMethodManager) o).showSoftInput(view, SHOW_IMPLICIT);
@@ -74,4 +75,5 @@ public abstract class BaseActivity extends AppCompatActivity {
Object o = getSystemService(INPUT_METHOD_SERVICE); Object o = getSystemService(INPUT_METHOD_SERVICE);
((InputMethodManager) o).hideSoftInputFromWindow(token, 0); ((InputMethodManager) o).hideSoftInputFromWindow(token, 0);
} }
} }

View File

@@ -1,5 +1,6 @@
package org.briarproject.android; package org.briarproject.android;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Configuration; import android.content.res.Configuration;
@@ -48,6 +49,8 @@ import static java.util.logging.Level.WARNING;
public class NavDrawerActivity extends BriarFragmentActivity implements public class NavDrawerActivity extends BriarFragmentActivity implements
BaseFragment.BaseFragmentListener, EventListener { BaseFragment.BaseFragmentListener, EventListener {
public final static String PREF_SEEN_WELCOME_MESSAGE = "welcome_message";
public static final String INTENT_CONTACTS = "intent_contacts"; public static final String INTENT_CONTACTS = "intent_contacts";
public static final String INTENT_FORUMS = "intent_forums"; public static final String INTENT_FORUMS = "intent_forums";
@@ -137,8 +140,7 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
} }
private void welcomeMessageCheck() { private void welcomeMessageCheck() {
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
MODE_PRIVATE);
if (!prefs.getBoolean(PREF_SEEN_WELCOME_MESSAGE, false)) { if (!prefs.getBoolean(PREF_SEEN_WELCOME_MESSAGE, false)) {
showMessageDialog(R.string.dialog_title_welcome, showMessageDialog(R.string.dialog_title_welcome,
R.string.dialog_welcome_message); R.string.dialog_welcome_message);

View File

@@ -16,14 +16,10 @@ import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener; import android.widget.TextView.OnEditorActionListener;
import org.briarproject.R; import org.briarproject.R;
import org.briarproject.android.event.PasswordValidateEvent;
import org.briarproject.android.helper.PasswordHelper;
import org.briarproject.android.util.AndroidUtils; import org.briarproject.android.util.AndroidUtils;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.event.Event;
import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.db.DatabaseConfig;
import org.briarproject.util.StringUtils;
import java.util.concurrent.Executor;
import javax.inject.Inject; import javax.inject.Inject;
@@ -34,28 +30,22 @@ import static android.view.View.VISIBLE;
public class PasswordActivity extends BaseActivity { public class PasswordActivity extends BaseActivity {
@Inject @CryptoExecutor protected Executor cryptoExecutor;
private Button signInButton; private Button signInButton;
private ProgressBar progress; private ProgressBar progress;
private TextInputLayout input; private TextInputLayout input;
private EditText password; private EditText password;
private byte[] encrypted; @Inject
PasswordHelper passwordHelper;
// Fields that are accessed from background threads must be volatile
@Inject protected volatile CryptoComponent crypto;
@Inject protected volatile DatabaseConfig databaseConfig;
@Override @Override
public void onCreate(Bundle state) { public void onCreate(Bundle state) {
super.onCreate(state); super.onCreate(state);
String hex = getEncryptedDatabaseKey(); if (!passwordHelper.initialized()) {
if (hex == null || !databaseConfig.databaseExists()) {
clearSharedPrefsAndDeleteEverything(); clearSharedPrefsAndDeleteEverything();
return; return;
} }
encrypted = StringUtils.fromHexString(hex);
setContentView(R.layout.activity_password); setContentView(R.layout.activity_password);
signInButton = (Button) findViewById(R.id.btn_sign_in); signInButton = (Button) findViewById(R.id.btn_sign_in);
@@ -66,8 +56,7 @@ public class PasswordActivity extends BaseActivity {
@Override @Override
public boolean onEditorAction(TextView v, int actionId, public boolean onEditorAction(TextView v, int actionId,
KeyEvent event) { KeyEvent event) {
hideSoftKeyboard(password); validatePassword();
validatePassword(encrypted, password.getText());
return true; return true;
} }
}); });
@@ -103,7 +92,7 @@ public class PasswordActivity extends BaseActivity {
} }
private void clearSharedPrefsAndDeleteEverything() { private void clearSharedPrefsAndDeleteEverything() {
clearSharedPrefs(); passwordHelper.clearPrefs();
AndroidUtils.deleteAppData(this); AndroidUtils.deleteAppData(this);
setResult(RESULT_CANCELED); setResult(RESULT_CANCELED);
startActivity(new Intent(this, SetupActivity.class)); startActivity(new Intent(this, SetupActivity.class));
@@ -111,7 +100,7 @@ public class PasswordActivity extends BaseActivity {
} }
public void onSignInClick(View v) { public void onSignInClick(View v) {
validatePassword(encrypted, password.getText()); validatePassword();
} }
public void onForgottenPasswordClick(View v) { public void onForgottenPasswordClick(View v) {
@@ -132,47 +121,37 @@ public class PasswordActivity extends BaseActivity {
dialog.show(); dialog.show();
} }
private void validatePassword(final byte[] encrypted, Editable e) { private void validatePassword() {
hideSoftKeyboard(password); hideSoftKeyboard(password);
// Replace the button with a progress bar
signInButton.setVisibility(INVISIBLE); signInButton.setVisibility(INVISIBLE);
progress.setVisibility(VISIBLE); progress.setVisibility(VISIBLE);
// Decrypt the database key in a background thread passwordHelper.validatePassword(password.getText().toString());
final String password = e.toString();
cryptoExecutor.execute(new Runnable() {
public void run() {
byte[] key = crypto.decryptWithPassword(encrypted, password);
if (key == null) {
tryAgain();
} else {
databaseConfig.setEncryptionKey(new SecretKey(key));
setResultAndFinish();
}
}
});
} }
private void tryAgain() { @Override
runOnUiThread(new Runnable() { public void eventOccurred(Event e) {
public void run() { super.eventOccurred(e);
AndroidUtils.setError(input, getString(R.string.try_again), if (e instanceof PasswordValidateEvent) {
true); boolean validated = ((PasswordValidateEvent)e).passwordValidated();
signInButton.setVisibility(VISIBLE); if (validated) {
progress.setVisibility(INVISIBLE);
password.setText("");
// show the keyboard again
showSoftKeyboard(password);
}
});
}
private void setResultAndFinish() {
runOnUiThread(new Runnable() {
public void run() {
setResult(RESULT_OK); setResult(RESULT_OK);
finish(); finish();
} }
}); else {
tryAgain();
}
}
} }
private void tryAgain() {
AndroidUtils.setError(input, getString(R.string.try_again),
true);
signInButton.setVisibility(VISIBLE);
progress.setVisibility(INVISIBLE);
password.setText("");
// show the keyboard again
showSoftKeyboard(password);
}
} }

View File

@@ -15,6 +15,7 @@ import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener; import android.widget.TextView.OnEditorActionListener;
import org.briarproject.R; import org.briarproject.R;
import org.briarproject.android.helper.SetupHelper;
import org.briarproject.android.util.AndroidUtils; import org.briarproject.android.util.AndroidUtils;
import org.briarproject.android.util.StrengthMeter; import org.briarproject.android.util.StrengthMeter;
import org.briarproject.android.api.ReferenceManager; import org.briarproject.android.api.ReferenceManager;
@@ -45,17 +46,8 @@ import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENG
public class SetupActivity extends BaseActivity implements OnClickListener, public class SetupActivity extends BaseActivity implements OnClickListener,
OnEditorActionListener { OnEditorActionListener {
private static final Logger LOG = @Inject
Logger.getLogger(SetupActivity.class.getName()); SetupHelper setupHelper;
@Inject @CryptoExecutor protected Executor cryptoExecutor;
@Inject protected PasswordStrengthEstimator strengthEstimator;
// Fields that are accessed from background threads must be volatile
@Inject protected volatile CryptoComponent crypto;
@Inject protected volatile DatabaseConfig databaseConfig;
@Inject protected volatile AuthorFactory authorFactory;
@Inject protected volatile ReferenceManager referenceManager;
TextInputLayout nicknameEntryWrapper; TextInputLayout nicknameEntryWrapper;
TextInputLayout passwordEntryWrapper; TextInputLayout passwordEntryWrapper;
@@ -123,7 +115,8 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
String firstPassword = passwordEntry.getText().toString(); String firstPassword = passwordEntry.getText().toString();
String secondPassword = passwordConfirmation.getText().toString(); String secondPassword = passwordConfirmation.getText().toString();
boolean passwordsMatch = firstPassword.equals(secondPassword); boolean passwordsMatch = firstPassword.equals(secondPassword);
float strength = strengthEstimator.estimateStrength(firstPassword); // float strength = strengthEstimator.estimateStrength(firstPassword);
float strength = setupHelper.estimatePasswordStrength(firstPassword);
strengthMeter.setStrength(strength); strengthMeter.setStrength(strength);
AndroidUtils.setError(nicknameEntryWrapper, AndroidUtils.setError(nicknameEntryWrapper,
getString(R.string.name_too_long), getString(R.string.name_too_long),
@@ -150,41 +143,22 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
progress.setVisibility(VISIBLE); progress.setVisibility(VISIBLE);
final String nickname = nicknameEntry.getText().toString(); final String nickname = nicknameEntry.getText().toString();
final String password = passwordEntry.getText().toString(); final String password = passwordEntry.getText().toString();
// Store the DB key and create the identity in a background thread setupHelper.createIdentity(nickname, password);
cryptoExecutor.execute(new Runnable() { // // Store the DB key and create the identity in a background thread
public void run() { // cryptoExecutor.execute(new Runnable() {
SecretKey key = crypto.generateSecretKey(); // public void run() {
databaseConfig.setEncryptionKey(key); // SecretKey key = crypto.generateSecretKey();
String hex = encryptDatabaseKey(key, password); // databaseConfig.setEncryptionKey(key);
storeEncryptedDatabaseKey(hex); // String hex = encryptDatabaseKey(key, password);
LocalAuthor localAuthor = createLocalAuthor(nickname); // storeEncryptedDatabaseKey(hex);
showDashboard(referenceManager.putReference(localAuthor, // LocalAuthor localAuthor = createLocalAuthor(nickname);
LocalAuthor.class)); // showDashboard(referenceManager.putReference(localAuthor,
} // LocalAuthor.class));
}); // }
// });
} }
private String encryptDatabaseKey(SecretKey key, String password) {
long now = System.currentTimeMillis();
byte[] encrypted = crypto.encryptWithPassword(key.getBytes(), password);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Key derivation took " + duration + " ms");
return StringUtils.toHexString(encrypted);
}
private LocalAuthor createLocalAuthor(String nickname) {
long now = System.currentTimeMillis();
KeyPair keyPair = crypto.generateSignatureKeyPair();
byte[] publicKey = keyPair.getPublic().getEncoded();
byte[] privateKey = keyPair.getPrivate().getEncoded();
LocalAuthor localAuthor = authorFactory.createLocalAuthor(nickname,
publicKey, privateKey);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Identity creation took " + duration + " ms");
return localAuthor;
}
private void showDashboard(final long handle) { private void showDashboard(final long handle) {
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {

View File

@@ -9,9 +9,8 @@ import android.os.StrictMode.VmPolicy;
import android.support.v7.preference.PreferenceManager; import android.support.v7.preference.PreferenceManager;
import org.briarproject.R; import org.briarproject.R;
import org.briarproject.android.api.AndroidExecutor; import org.briarproject.android.helper.ConfigHelper;
import org.briarproject.android.util.AndroidUtils; import org.briarproject.android.util.AndroidUtils;
import org.briarproject.api.db.DatabaseConfig;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -29,9 +28,7 @@ public class SplashScreenActivity extends BaseActivity {
private static final long EXPIRY_DATE = 1464735600 * 1000L; private static final long EXPIRY_DATE = 1464735600 * 1000L;
@Inject @Inject
protected DatabaseConfig dbConfig; ConfigHelper configHelper;
@Inject
protected AndroidExecutor androidExecutor;
public SplashScreenActivity() { public SplashScreenActivity() {
Logger.getLogger("").setLevel(DEFAULT_LOG_LEVEL); Logger.getLogger("").setLevel(DEFAULT_LOG_LEVEL);
@@ -65,11 +62,10 @@ 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 {
String hex = getEncryptedDatabaseKey(); if (configHelper.initialized()) {
if (hex != null && dbConfig.databaseExists()) {
startActivity(new Intent(this, NavDrawerActivity.class)); startActivity(new Intent(this, NavDrawerActivity.class));
} else { } else {
clearSharedPrefs(); configHelper.clearPrefs();
AndroidUtils.deleteAppData(this); AndroidUtils.deleteAppData(this);
startActivity(new Intent(this, SetupActivity.class)); startActivity(new Intent(this, SetupActivity.class));
} }

View File

@@ -0,0 +1,6 @@
package org.briarproject.android.event;
import org.briarproject.api.event.EventBus;
public interface AppBus extends EventBus{
}

View File

@@ -0,0 +1,25 @@
package org.briarproject.android.event;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventListener;
import java.util.Collection;
import java.util.concurrent.CopyOnWriteArrayList;
public class AppBusImp implements AppBus {
private final Collection<EventListener> listeners =
new CopyOnWriteArrayList<EventListener>();
public void addListener(EventListener l) {
listeners.add(l);
}
public void removeListener(EventListener l) {
listeners.remove(l);
}
public void broadcast(Event e) {
for (EventListener l : listeners) l.eventOccurred(e);
}
}

View File

@@ -0,0 +1,10 @@
package org.briarproject.android.event;
import org.briarproject.api.event.Event;
public class ErrorEvent extends Event {
public ErrorEvent() {
}
}

View File

@@ -0,0 +1,16 @@
package org.briarproject.android.event;
import org.briarproject.api.event.Event;
public class LocalAuthorCreatedEvent extends Event {
private final long handle;
public LocalAuthorCreatedEvent(long handle) {
this.handle = handle;
}
public long getAuthorHandle() {
return handle;
}
}

View File

@@ -0,0 +1,16 @@
package org.briarproject.android.event;
import org.briarproject.api.event.Event;
public class PasswordValidateEvent extends Event {
private final boolean passwordValidated;
public PasswordValidateEvent(boolean passwordValidated) {
this.passwordValidated = passwordValidated;
}
public boolean passwordValidated() {
return passwordValidated;
}
}

View File

@@ -0,0 +1,9 @@
package org.briarproject.android.helper;
public interface ConfigHelper {
String getEncryptedDatabaseKey();
void clearPrefs();
boolean initialized();
}

View File

@@ -0,0 +1,41 @@
package org.briarproject.android.helper;
import android.content.SharedPreferences;
import org.briarproject.api.db.DatabaseConfig;
import javax.inject.Inject;
public class ConfigHelperImp implements ConfigHelper {
private final static String PREF_DB_KEY = "key";
@Inject
protected SharedPreferences briarPrefs;
@Inject
protected volatile DatabaseConfig databaseConfig;
@Inject
public ConfigHelperImp() {
}
public String getEncryptedDatabaseKey() {
return briarPrefs.getString(PREF_DB_KEY, null);
}
public void clearPrefs() {
SharedPreferences.Editor editor = briarPrefs.edit();
editor.clear();
editor.apply();
}
@Override
public boolean initialized() {
String hex = getEncryptedDatabaseKey();
if (hex != null && databaseConfig.databaseExists()) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,5 @@
package org.briarproject.android.helper;
public interface PasswordHelper extends ConfigHelper {
void validatePassword(String password);
}

View File

@@ -0,0 +1,70 @@
package org.briarproject.android.helper;
import android.app.Activity;
import org.briarproject.android.event.AppBus;
import org.briarproject.android.event.ErrorEvent;
import org.briarproject.android.event.PasswordValidateEvent;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.crypto.SecretKey;
import org.briarproject.util.StringUtils;
import java.util.concurrent.Executor;
import javax.inject.Inject;
public class PasswordHelperImp extends ConfigHelperImp
implements PasswordHelper {
@Inject
@CryptoExecutor
protected Executor cryptoExecutor;
@Inject
protected CryptoComponent crypto;
@Inject
protected Activity activity;
@Inject
protected AppBus appBus;
@Inject
public PasswordHelperImp() {
}
@Override
public void validatePassword(final String password) {
final byte[] encrypted = getEncryptedKey();
if (encrypted == null) {
appBus.broadcast(new ErrorEvent());
}
cryptoExecutor.execute(new Runnable() {
public void run() {
byte[] key = crypto.decryptWithPassword(encrypted, password);
if (key == null) {
// tryAgain();.
onPasswordValidated(false);
} else {
databaseConfig.setEncryptionKey(new SecretKey(key));
onPasswordValidated(true);
// setResultAndFinish();
}
}
});
}
private void onPasswordValidated(final boolean validated) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
appBus.broadcast(new PasswordValidateEvent(validated));
}
});
}
private byte[] getEncryptedKey() {
String hex = getEncryptedDatabaseKey();
return hex == null? null : StringUtils.fromHexString(hex);
}
}

View File

@@ -0,0 +1,6 @@
package org.briarproject.android.helper;
public interface SetupHelper {
float estimatePasswordStrength(String password);
void createIdentity(String nickname, String password);
}

View File

@@ -0,0 +1,119 @@
package org.briarproject.android.helper;
import android.app.Activity;
import android.content.SharedPreferences;
import org.briarproject.android.api.ReferenceManager;
import org.briarproject.android.event.AppBus;
import org.briarproject.android.event.LocalAuthorCreatedEvent;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.crypto.KeyPair;
import org.briarproject.api.crypto.PasswordStrengthEstimator;
import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.db.DatabaseConfig;
import org.briarproject.api.identity.AuthorFactory;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.util.StringUtils;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.inject.Inject;
import static java.util.logging.Level.INFO;
public class SetupHelperImp implements SetupHelper {
private static final Logger LOG =
Logger.getLogger(SetupHelperImp.class.getName());
private final static String PREF_DB_KEY = "key";
@Inject
@CryptoExecutor
protected Executor cryptoExecutor;
@Inject
protected PasswordStrengthEstimator strengthEstimator;
// Fields that are accessed from background threads must be volatile
@Inject
protected volatile CryptoComponent crypto;
@Inject
protected volatile DatabaseConfig databaseConfig;
@Inject
protected volatile AuthorFactory authorFactory;
@Inject
protected volatile ReferenceManager referenceManager;
@Inject
protected Activity activity;
@Inject
protected SharedPreferences briarPrefs;
@Inject
protected AppBus appBus;
@Inject
public SetupHelperImp() {
}
private String encryptDatabaseKey(SecretKey key, String password) {
long now = System.currentTimeMillis();
byte[] encrypted = crypto.encryptWithPassword(key.getBytes(), password);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Key derivation took " + duration + " ms");
return StringUtils.toHexString(encrypted);
}
private LocalAuthor createLocalAuthor(String nickname) {
long now = System.currentTimeMillis();
KeyPair keyPair = crypto.generateSignatureKeyPair();
byte[] publicKey = keyPair.getPublic().getEncoded();
byte[] privateKey = keyPair.getPrivate().getEncoded();
LocalAuthor localAuthor = authorFactory.createLocalAuthor(nickname,
publicKey, privateKey);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Identity creation took " + duration + " ms");
return localAuthor;
}
@Override
public float estimatePasswordStrength(String password) {
return strengthEstimator.estimateStrength(password);
}
@Override
public void createIdentity(final String nickname, final String password) {
cryptoExecutor.execute(new Runnable() {
public void run() {
SecretKey key = crypto.generateSecretKey();
databaseConfig.setEncryptionKey(key);
String hex = encryptDatabaseKey(key, password);
storeEncryptedDatabaseKey(hex);
final LocalAuthor localAuthor = createLocalAuthor(nickname);
onIdentityCreated(referenceManager.putReference(localAuthor,
LocalAuthor.class));
}
});
}
private void onIdentityCreated(final long handle) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
appBus.broadcast(new LocalAuthorCreatedEvent(handle));
}
});
}
private void storeEncryptedDatabaseKey(final String hex) {
SharedPreferences.Editor editor = briarPrefs.edit();
editor.putString(PREF_DB_KEY, hex);
editor.apply();
}
}

View File

@@ -10,7 +10,7 @@ import android.support.v7.preference.PreferenceManager;
import org.briarproject.android.ActivityComponent; import org.briarproject.android.ActivityComponent;
import org.briarproject.android.AndroidComponent; import org.briarproject.android.AndroidComponent;
import org.briarproject.android.BriarActivity; import org.briarproject.android.BriarActivity;
import org.briarproject.android.api.AndroidExecutor; import org.briarproject.android.helper.ConfigHelper;
import org.briarproject.android.util.AndroidUtils; import org.briarproject.android.util.AndroidUtils;
import org.briarproject.api.db.DatabaseConfig; import org.briarproject.api.db.DatabaseConfig;
import org.iilab.IilabEngineeringRSA2048Pin; import org.iilab.IilabEngineeringRSA2048Pin;
@@ -24,7 +24,6 @@ import info.guardianproject.panic.Panic;
import info.guardianproject.panic.PanicResponder; import info.guardianproject.panic.PanicResponder;
import info.guardianproject.trustedintents.TrustedIntents; import info.guardianproject.trustedintents.TrustedIntents;
import static android.content.Intent.ACTION_DELETE;
import static org.briarproject.android.panic.PanicPreferencesFragment.KEY_LOCK; import static org.briarproject.android.panic.PanicPreferencesFragment.KEY_LOCK;
import static org.briarproject.android.panic.PanicPreferencesFragment.KEY_PURGE; import static org.briarproject.android.panic.PanicPreferencesFragment.KEY_PURGE;
import static org.briarproject.android.panic.PanicPreferencesFragment.KEY_UNINSTALL; import static org.briarproject.android.panic.PanicPreferencesFragment.KEY_UNINSTALL;
@@ -33,11 +32,7 @@ public class PanicResponderActivity extends BriarActivity {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(PanicResponderActivity.class.getName()); Logger.getLogger(PanicResponderActivity.class.getName());
@Inject protected ConfigHelper configHelper;
@Inject
protected DatabaseConfig databaseConfig;
@Inject
protected AndroidExecutor androidExecutor;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@@ -113,7 +108,7 @@ public class PanicResponderActivity extends BriarActivity {
private void deleteAllData() { private void deleteAllData() {
androidExecutor.execute(new Runnable() { androidExecutor.execute(new Runnable() {
public void run() { public void run() {
clearSharedPrefs(); configHelper.clearPrefs();
// TODO somehow delete/shred the database more thoroughly // TODO somehow delete/shred the database more thoroughly
AndroidUtils.deleteAppData(PanicResponderActivity.this); AndroidUtils.deleteAppData(PanicResponderActivity.this);
PanicResponder.deleteAllAppData(PanicResponderActivity.this); PanicResponder.deleteAllAppData(PanicResponderActivity.this);

View File

@@ -1,4 +0,0 @@
package org.briarproject.android.sdk;
public interface BriarHelper {
}

View File

@@ -1,13 +0,0 @@
package org.briarproject.android.sdk;
import javax.inject.Inject;
public class BriarHelperImp implements BriarHelper {
@Inject
public BriarHelperImp() {
}
}