mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Show a dialog if the DB key can't be decrypted due to a keystore error.
This commit is contained in:
@@ -36,6 +36,7 @@ import org.briarproject.bramble.util.AndroidUtils;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
import org.briarproject.briar.android.account.LockManagerImpl;
|
||||
import org.briarproject.briar.android.keyagreement.ContactExchangeModule;
|
||||
import org.briarproject.briar.android.login.LoginModule;
|
||||
import org.briarproject.briar.android.viewmodel.ViewModelModule;
|
||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||
import org.briarproject.briar.api.android.DozeWatchdog;
|
||||
@@ -64,7 +65,11 @@ import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONIO
|
||||
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX;
|
||||
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
||||
|
||||
@Module(includes = {ContactExchangeModule.class, ViewModelModule.class})
|
||||
@Module(includes = {
|
||||
ContactExchangeModule.class,
|
||||
LoginModule.class,
|
||||
ViewModelModule.class
|
||||
})
|
||||
public class AppModule {
|
||||
|
||||
static class EagerSingletons {
|
||||
|
||||
@@ -8,8 +8,6 @@ import org.briarproject.briar.android.controller.BriarController;
|
||||
import org.briarproject.briar.android.controller.BriarControllerImpl;
|
||||
import org.briarproject.briar.android.controller.DbController;
|
||||
import org.briarproject.briar.android.controller.DbControllerImpl;
|
||||
import org.briarproject.briar.android.login.ChangePasswordController;
|
||||
import org.briarproject.briar.android.login.ChangePasswordControllerImpl;
|
||||
import org.briarproject.briar.android.navdrawer.NavDrawerController;
|
||||
import org.briarproject.briar.android.navdrawer.NavDrawerControllerImpl;
|
||||
|
||||
@@ -46,13 +44,6 @@ public class ActivityModule {
|
||||
return setupController;
|
||||
}
|
||||
|
||||
@ActivityScope
|
||||
@Provides
|
||||
ChangePasswordController providePasswordController(
|
||||
ChangePasswordControllerImpl passwordController) {
|
||||
return passwordController;
|
||||
}
|
||||
|
||||
@ActivityScope
|
||||
@Provides
|
||||
protected BriarController provideBriarController(
|
||||
@@ -80,5 +71,4 @@ public class ActivityModule {
|
||||
BriarServiceConnection provideBriarServiceConnection() {
|
||||
return new BriarServiceConnection();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,27 +15,32 @@ import android.widget.Toast;
|
||||
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.DecryptionResult;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.activity.BriarActivity;
|
||||
import org.briarproject.briar.android.controller.handler.UiResultHandler;
|
||||
import org.briarproject.briar.android.util.UiUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
import static android.view.View.INVISIBLE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static android.widget.Toast.LENGTH_LONG;
|
||||
import static org.briarproject.bramble.api.crypto.DecryptionResult.KEY_STRENGTHENER_ERROR;
|
||||
import static org.briarproject.bramble.api.crypto.DecryptionResult.SUCCESS;
|
||||
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
|
||||
import static org.briarproject.briar.android.login.LoginUtils.createKeyStrengthenerErrorDialog;
|
||||
import static org.briarproject.briar.android.util.UiUtils.hideSoftKeyboard;
|
||||
import static org.briarproject.briar.android.util.UiUtils.setError;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showSoftKeyboard;
|
||||
|
||||
public class ChangePasswordActivity extends BriarActivity
|
||||
implements OnClickListener, OnEditorActionListener {
|
||||
|
||||
@Inject
|
||||
protected ChangePasswordController passwordController;
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
|
||||
private TextInputLayout currentPasswordEntryWrapper;
|
||||
private TextInputLayout newPasswordEntryWrapper;
|
||||
@@ -47,11 +52,17 @@ public class ChangePasswordActivity extends BriarActivity
|
||||
private Button changePasswordButton;
|
||||
private ProgressBar progress;
|
||||
|
||||
// Package access for testing
|
||||
ChangePasswordViewModel viewModel;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
super.onCreate(state);
|
||||
setContentView(R.layout.activity_change_password);
|
||||
|
||||
viewModel = ViewModelProviders.of(this, viewModelFactory)
|
||||
.get(ChangePasswordViewModel.class);
|
||||
|
||||
currentPasswordEntryWrapper =
|
||||
findViewById(R.id.current_password_entry_wrapper);
|
||||
newPasswordEntryWrapper = findViewById(R.id.new_password_entry_wrapper);
|
||||
@@ -102,13 +113,12 @@ public class ChangePasswordActivity extends BriarActivity
|
||||
String firstPassword = newPassword.getText().toString();
|
||||
String secondPassword = newPasswordConfirmation.getText().toString();
|
||||
boolean passwordsMatch = firstPassword.equals(secondPassword);
|
||||
float strength =
|
||||
passwordController.estimatePasswordStrength(firstPassword);
|
||||
float strength = viewModel.estimatePasswordStrength(firstPassword);
|
||||
strengthMeter.setStrength(strength);
|
||||
UiUtils.setError(newPasswordEntryWrapper,
|
||||
setError(newPasswordEntryWrapper,
|
||||
getString(R.string.password_too_weak),
|
||||
firstPassword.length() > 0 && strength < QUITE_WEAK);
|
||||
UiUtils.setError(newPasswordConfirmationWrapper,
|
||||
setError(newPasswordConfirmationWrapper,
|
||||
getString(R.string.passwords_do_not_match),
|
||||
secondPassword.length() > 0 && !passwordsMatch);
|
||||
changePasswordButton.setEnabled(
|
||||
@@ -127,32 +137,34 @@ public class ChangePasswordActivity extends BriarActivity
|
||||
// Replace the button with a progress bar
|
||||
changePasswordButton.setVisibility(INVISIBLE);
|
||||
progress.setVisibility(VISIBLE);
|
||||
passwordController.changePassword(currentPassword.getText().toString(),
|
||||
newPassword.getText().toString(),
|
||||
new UiResultHandler<Boolean>(this) {
|
||||
@Override
|
||||
public void onResultUi(@NonNull Boolean result) {
|
||||
if (result) {
|
||||
Toast.makeText(ChangePasswordActivity.this,
|
||||
R.string.password_changed,
|
||||
Toast.LENGTH_LONG).show();
|
||||
setResult(RESULT_OK);
|
||||
supportFinishAfterTransition();
|
||||
} else {
|
||||
tryAgain();
|
||||
}
|
||||
|
||||
String curPwd = currentPassword.getText().toString();
|
||||
String newPwd = newPassword.getText().toString();
|
||||
viewModel.changePassword(curPwd, newPwd).observeEvent(this, result -> {
|
||||
if (result == SUCCESS) {
|
||||
Toast.makeText(ChangePasswordActivity.this,
|
||||
R.string.password_changed,
|
||||
LENGTH_LONG).show();
|
||||
setResult(RESULT_OK);
|
||||
supportFinishAfterTransition();
|
||||
} else {
|
||||
tryAgain(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void tryAgain() {
|
||||
UiUtils.setError(currentPasswordEntryWrapper,
|
||||
getString(R.string.try_again), true);
|
||||
private void tryAgain(DecryptionResult result) {
|
||||
changePasswordButton.setVisibility(VISIBLE);
|
||||
progress.setVisibility(INVISIBLE);
|
||||
currentPassword.setText("");
|
||||
|
||||
// show the keyboard again
|
||||
showSoftKeyboard(currentPassword);
|
||||
if (result == KEY_STRENGTHENER_ERROR) {
|
||||
createKeyStrengthenerErrorDialog(this).show();
|
||||
} else {
|
||||
setError(currentPasswordEntryWrapper,
|
||||
getString(R.string.try_again), true);
|
||||
currentPassword.setText("");
|
||||
// show the keyboard again
|
||||
showSoftKeyboard(currentPassword);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package org.briarproject.briar.android.login;
|
||||
|
||||
import org.briarproject.bramble.api.account.AccountManager;
|
||||
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.android.controller.handler.ResultHandler;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@NotNullByDefault
|
||||
public class ChangePasswordControllerImpl implements ChangePasswordController {
|
||||
|
||||
protected final AccountManager accountManager;
|
||||
protected final Executor ioExecutor;
|
||||
private final PasswordStrengthEstimator strengthEstimator;
|
||||
|
||||
@Inject
|
||||
ChangePasswordControllerImpl(AccountManager accountManager,
|
||||
@IoExecutor Executor ioExecutor,
|
||||
PasswordStrengthEstimator strengthEstimator) {
|
||||
this.accountManager = accountManager;
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.strengthEstimator = strengthEstimator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float estimatePasswordStrength(String password) {
|
||||
return strengthEstimator.estimateStrength(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changePassword(String oldPassword, String newPassword,
|
||||
ResultHandler<Boolean> resultHandler) {
|
||||
ioExecutor.execute(() -> {
|
||||
boolean changed =
|
||||
accountManager.changePassword(oldPassword, newPassword);
|
||||
resultHandler.onResult(changed);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.briarproject.briar.android.login;
|
||||
|
||||
import org.briarproject.bramble.api.account.AccountManager;
|
||||
import org.briarproject.bramble.api.crypto.DecryptionException;
|
||||
import org.briarproject.bramble.api.crypto.DecryptionResult;
|
||||
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
||||
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import static org.briarproject.bramble.api.crypto.DecryptionResult.SUCCESS;
|
||||
|
||||
@NotNullByDefault
|
||||
public class ChangePasswordViewModel extends ViewModel {
|
||||
|
||||
private final AccountManager accountManager;
|
||||
private final Executor ioExecutor;
|
||||
private final PasswordStrengthEstimator strengthEstimator;
|
||||
|
||||
@Inject
|
||||
ChangePasswordViewModel(AccountManager accountManager,
|
||||
@IoExecutor Executor ioExecutor,
|
||||
PasswordStrengthEstimator strengthEstimator) {
|
||||
this.accountManager = accountManager;
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.strengthEstimator = strengthEstimator;
|
||||
}
|
||||
|
||||
float estimatePasswordStrength(String password) {
|
||||
return strengthEstimator.estimateStrength(password);
|
||||
}
|
||||
|
||||
LiveEvent<DecryptionResult> changePassword(String oldPassword,
|
||||
String newPassword) {
|
||||
MutableLiveEvent<DecryptionResult> result = new MutableLiveEvent<>();
|
||||
ioExecutor.execute(() -> {
|
||||
try {
|
||||
accountManager.changePassword(oldPassword, newPassword);
|
||||
result.postEvent(SUCCESS);
|
||||
} catch (DecryptionException e) {
|
||||
result.postEvent(e.getDecryptionResult());
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.briarproject.briar.android.login;
|
||||
|
||||
import org.briarproject.briar.android.viewmodel.ViewModelKey;
|
||||
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.multibindings.IntoMap;
|
||||
|
||||
@Module
|
||||
public abstract class LoginModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(StartupViewModel.class)
|
||||
abstract ViewModel bindStartupViewModel(StartupViewModel viewModel);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(ChangePasswordViewModel.class)
|
||||
abstract ViewModel bindChangePasswordViewModel(
|
||||
ChangePasswordViewModel viewModel);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.briarproject.briar.android.login;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import static androidx.core.content.ContextCompat.getColor;
|
||||
import static androidx.core.content.ContextCompat.getDrawable;
|
||||
import static androidx.core.graphics.drawable.DrawableCompat.setTint;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@NotNullByDefault
|
||||
class LoginUtils {
|
||||
|
||||
static AlertDialog createKeyStrengthenerErrorDialog(Context ctx) {
|
||||
AlertDialog.Builder builder =
|
||||
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
|
||||
Drawable icon = getDrawable(ctx, R.drawable.alerts_and_states_error);
|
||||
setTint(requireNonNull(icon), getColor(ctx, R.color.color_primary));
|
||||
builder.setIcon(icon);
|
||||
builder.setTitle(R.string.dialog_title_cannot_check_password);
|
||||
builder.setMessage(R.string.dialog_message_cannot_check_password);
|
||||
builder.setPositiveButton(R.string.ok, null);
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import android.widget.ProgressBar;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.DecryptionResult;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
@@ -28,6 +29,9 @@ import androidx.lifecycle.ViewModelProviders;
|
||||
import static android.view.View.INVISIBLE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
||||
import static org.briarproject.bramble.api.crypto.DecryptionResult.KEY_STRENGTHENER_ERROR;
|
||||
import static org.briarproject.bramble.api.crypto.DecryptionResult.SUCCESS;
|
||||
import static org.briarproject.briar.android.login.LoginUtils.createKeyStrengthenerErrorDialog;
|
||||
import static org.briarproject.briar.android.util.UiUtils.enterPressed;
|
||||
import static org.briarproject.briar.android.util.UiUtils.hideSoftKeyboard;
|
||||
import static org.briarproject.briar.android.util.UiUtils.setError;
|
||||
@@ -58,12 +62,13 @@ public class PasswordFragment extends BaseFragment implements TextWatcher {
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.fragment_password, container,
|
||||
false);
|
||||
false);
|
||||
|
||||
viewModel = ViewModelProviders.of(requireActivity(), viewModelFactory)
|
||||
.get(StartupViewModel.class);
|
||||
viewModel.getPasswordValidated().observeEvent(this, valid -> {
|
||||
if (!valid) onPasswordInvalid();
|
||||
|
||||
viewModel.getPasswordValidated().observeEvent(this, result -> {
|
||||
if (result != SUCCESS) onPasswordInvalid(result);
|
||||
});
|
||||
|
||||
signInButton = v.findViewById(R.id.btn_sign_in);
|
||||
@@ -107,18 +112,20 @@ public class PasswordFragment extends BaseFragment implements TextWatcher {
|
||||
viewModel.validatePassword(password.getText().toString());
|
||||
}
|
||||
|
||||
private void onPasswordInvalid() {
|
||||
setError(input, getString(R.string.try_again), true);
|
||||
private void onPasswordInvalid(DecryptionResult result) {
|
||||
signInButton.setVisibility(VISIBLE);
|
||||
progress.setVisibility(INVISIBLE);
|
||||
password.setText(null);
|
||||
|
||||
// show the keyboard again
|
||||
showSoftKeyboard(password);
|
||||
if (result == KEY_STRENGTHENER_ERROR) {
|
||||
createKeyStrengthenerErrorDialog(requireContext()).show();
|
||||
} else {
|
||||
setError(input, getString(R.string.try_again), true);
|
||||
password.setText(null);
|
||||
// show the keyboard again
|
||||
showSoftKeyboard(password);
|
||||
}
|
||||
}
|
||||
|
||||
public void onForgottenPasswordClick() {
|
||||
// TODO Encapsulate the dialog in a re-usable fragment
|
||||
private void onForgottenPasswordClick() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
|
||||
R.style.BriarDialogTheme);
|
||||
builder.setTitle(R.string.dialog_title_lost_password);
|
||||
|
||||
@@ -3,6 +3,8 @@ package org.briarproject.briar.android.login;
|
||||
import android.app.Application;
|
||||
|
||||
import org.briarproject.bramble.api.account.AccountManager;
|
||||
import org.briarproject.bramble.api.crypto.DecryptionException;
|
||||
import org.briarproject.bramble.api.crypto.DecryptionResult;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.event.EventListener;
|
||||
@@ -24,6 +26,7 @@ import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import static org.briarproject.bramble.api.crypto.DecryptionResult.SUCCESS;
|
||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.COMPACTING_DATABASE;
|
||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
|
||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES;
|
||||
@@ -46,7 +49,7 @@ public class StartupViewModel extends AndroidViewModel
|
||||
@IoExecutor
|
||||
private final Executor ioExecutor;
|
||||
|
||||
private final MutableLiveEvent<Boolean> passwordValidated =
|
||||
private final MutableLiveEvent<DecryptionResult> passwordValidated =
|
||||
new MutableLiveEvent<>();
|
||||
private final MutableLiveEvent<Boolean> accountDeleted =
|
||||
new MutableLiveEvent<>();
|
||||
@@ -105,13 +108,17 @@ public class StartupViewModel extends AndroidViewModel
|
||||
|
||||
void validatePassword(String password) {
|
||||
ioExecutor.execute(() -> {
|
||||
boolean signedIn = accountManager.signIn(password);
|
||||
passwordValidated.postEvent(signedIn);
|
||||
if (signedIn) state.postValue(SIGNED_IN);
|
||||
try {
|
||||
accountManager.signIn(password);
|
||||
passwordValidated.postEvent(SUCCESS);
|
||||
state.postValue(SIGNED_IN);
|
||||
} catch (DecryptionException e) {
|
||||
passwordValidated.postEvent(e.getDecryptionResult());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
LiveEvent<Boolean> getPasswordValidated() {
|
||||
LiveEvent<DecryptionResult> getPasswordValidated() {
|
||||
return passwordValidated;
|
||||
}
|
||||
|
||||
|
||||
@@ -381,7 +381,7 @@ public class UiUtils {
|
||||
/**
|
||||
* Same as {@link #observeOnce(LiveData, LifecycleOwner, Observer)},
|
||||
* but without a {@link LifecycleOwner}.
|
||||
*
|
||||
* <p>
|
||||
* Warning: Do NOT call from objects that have a lifecycle.
|
||||
*/
|
||||
@UiThread
|
||||
@@ -401,5 +401,4 @@ public class UiUtils {
|
||||
return ctx.getResources().getConfiguration().getLayoutDirection() ==
|
||||
LAYOUT_DIRECTION_RTL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import org.briarproject.briar.android.contact.add.remote.AddContactViewModel;
|
||||
import org.briarproject.briar.android.contact.add.remote.PendingContactListViewModel;
|
||||
import org.briarproject.briar.android.conversation.ConversationViewModel;
|
||||
import org.briarproject.briar.android.conversation.ImageViewModel;
|
||||
import org.briarproject.briar.android.login.StartupViewModel;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@@ -17,11 +16,6 @@ import dagger.multibindings.IntoMap;
|
||||
@Module
|
||||
public abstract class ViewModelModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(StartupViewModel.class)
|
||||
abstract ViewModel bindStartupViewModel(StartupViewModel startupViewModel);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(ConversationViewModel.class)
|
||||
|
||||
Reference in New Issue
Block a user