Restore account activity/view model

This commit is contained in:
ameba23
2021-04-21 16:34:56 +02:00
parent afc0bc3f3c
commit 5c22d233ef
4 changed files with 212 additions and 39 deletions

View File

@@ -94,8 +94,10 @@ import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardFragm
import org.briarproject.briar.android.socialbackup.ShardsSentFragment;
import org.briarproject.briar.android.socialbackup.ThresholdSelectorFragment;
import org.briarproject.briar.android.socialbackup.creation.CreateBackupModule;
import org.briarproject.briar.android.socialbackup.recover.RestoreAccountActivity;
import org.briarproject.briar.android.splash.SplashScreenActivity;
import org.briarproject.briar.android.test.TestDataActivity;
import org.briarproject.briar.api.socialbackup.recovery.RestoreAccount;
import dagger.Component;
@@ -206,6 +208,8 @@ public interface ActivityComponent {
void inject(OwnerRecoveryModeMainFragment ownerRecoveryModeMainFragment);
void inject(RestoreAccountActivity restoreAccountActivity);
// Fragments
void inject(AuthorNameFragment fragment);

View File

@@ -15,12 +15,12 @@ import org.briarproject.briar.android.contact.add.nearby.QrCodeUtils;
import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import org.briarproject.briar.api.socialbackup.BackupPayload;
import org.briarproject.briar.api.socialbackup.DarkCrystal;
import org.briarproject.briar.api.socialbackup.ReturnShardPayload;
import org.briarproject.briar.api.socialbackup.Shard;
import org.briarproject.briar.api.socialbackup.recovery.RestoreAccount;
import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask;
import org.briarproject.briar.socialbackup.BackupPayloadDecoder;
import org.briarproject.briar.socialbackup.SocialBackup;
import org.briarproject.briar.api.socialbackup.SocialBackup;
import java.net.InetAddress;
import java.net.UnknownHostException;
@@ -56,8 +56,7 @@ class OwnerReturnShardViewModel extends AndroidViewModel
private final AndroidExecutor androidExecutor;
private final Executor ioExecutor;
private final SecretOwnerTask task;
private final DarkCrystal darkCrystal;
private final BackupPayloadDecoder backupPayloadDecoder;
private final RestoreAccount restoreAccount;
private final MutableLiveEvent<Boolean> showQrCodeFragment =
new MutableLiveEvent<>();
@@ -67,7 +66,6 @@ class OwnerReturnShardViewModel extends AndroidViewModel
new MutableLiveEvent<>();
private boolean wasContinueClicked = false;
private boolean isActivityResumed = false;
private ArrayList<ReturnShardPayload> recoveredShards = new ArrayList<>();
private Bitmap qrCodeBitmap;
private WifiManager wifiManager;
private SecretKey secretKey;
@@ -76,14 +74,12 @@ class OwnerReturnShardViewModel extends AndroidViewModel
OwnerReturnShardViewModel(Application app,
AndroidExecutor androidExecutor,
SecretOwnerTask task,
DarkCrystal darkCrystal,
BackupPayloadDecoder backupPayloadDecoder,
RestoreAccount restoreAccount,
@IoExecutor Executor ioExecutor) {
super(app);
this.androidExecutor = androidExecutor;
this.ioExecutor = ioExecutor;
this.backupPayloadDecoder = backupPayloadDecoder;
this.darkCrystal = darkCrystal;
this.restoreAccount = restoreAccount;
this.task = task;
wifiManager = (WifiManager) app.getSystemService(WIFI_SERVICE);
@@ -196,7 +192,7 @@ class OwnerReturnShardViewModel extends AndroidViewModel
}
public int getNumberOfShards() {
return recoveredShards.size();
return restoreAccount.getNumberOfShards();
}
@Override
@@ -227,38 +223,14 @@ class OwnerReturnShardViewModel extends AndroidViewModel
// TODO figure out how to actually use a hash set for these objects
public boolean addToShardSet(ReturnShardPayload toAdd) {
boolean found = false;
for (ReturnShardPayload returnShardPayload : recoveredShards) {
if (toAdd.equals(returnShardPayload)) {
found = true;
break;
}
}
if (!found) recoveredShards.add(toAdd);
return !found;
return restoreAccount.addReturnShardPayload(toAdd);
}
public boolean canRecover() {
ArrayList<Shard> shards = new ArrayList();
for (ReturnShardPayload returnShardPayload : recoveredShards) {
// TODO check shards all have same secret id
shards.add(returnShardPayload.getShard());
}
try {
secretKey = darkCrystal.combineShards(shards);
} catch (GeneralSecurityException e) {
// TODO handle error message
return false;
}
return true;
return restoreAccount.canRecover();
}
public int recover() throws FormatException, GeneralSecurityException {
if (secretKey == null) throw new GeneralSecurityException();
// TODO find backup with highest version number
BackupPayload backupPayload = recoveredShards.get(0).getBackupPayload();
SocialBackup decodedBackup = backupPayloadDecoder.decodeBackupPayload(secretKey, backupPayload);
int version = decodedBackup.getVersion();
return version;
return restoreAccount.recover();
}
}

View File

@@ -1,4 +1,83 @@
package org.briarproject.briar.android.socialbackup.recover;
public class RestoreAccountActivity {
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Bundle;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.account.DozeFragment;
import org.briarproject.briar.android.account.SetPasswordFragment;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BaseActivity;
import org.briarproject.briar.android.fragment.BaseFragment;
import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.lifecycle.ViewModelProvider;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
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_TASK_ON_HOME;
import static org.briarproject.briar.android.BriarApplication.ENTRY_ACTIVITY;
import static org.briarproject.briar.android.socialbackup.recover.RestoreAccountViewModel.State;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class RestoreAccountActivity extends BaseActivity
implements BaseFragment.BaseFragmentListener {
@Inject
ViewModelProvider.Factory viewModelFactory;
RestoreAccountViewModel viewModel;
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
viewModel = new ViewModelProvider(this, viewModelFactory)
.get(RestoreAccountViewModel.class);
viewModel.getState().observeEvent(this, this::onStateChanged);
}
@Override
public void onCreate(@Nullable Bundle state) {
super.onCreate(state);
setContentView(R.layout.activity_fragment_container);
}
private void onStateChanged(RestoreAccountViewModel.State state) {
if (state == RestoreAccountViewModel.State.SET_PASSWORD) {
showInitialFragment(SetPasswordFragment.newInstance());
} else if (state == State.DOZE) {
showDozeFragment();
} else if (state == State.CREATED || state == State.FAILED) {
// TODO: Show an error if failed
showApp();
}
}
@TargetApi(23)
void showDozeFragment() {
showNextFragment(DozeFragment.newInstance());
}
void showApp() {
Intent i = new Intent(this, ENTRY_ACTIVITY);
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME |
FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
supportFinishAfterTransition();
overridePendingTransition(R.anim.screen_new_in, R.anim.screen_old_out);
}
@Override
@Deprecated
public void runOnDbThread(Runnable runnable) {
throw new RuntimeException("Don't use this deprecated method here.");
}
}

View File

@@ -1,4 +1,122 @@
package org.briarproject.briar.android.socialbackup.recover;
public class RestoreAccountViewModel {
import android.app.Application;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.account.DozeHelper;
import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import org.briarproject.briar.api.socialbackup.recovery.RestoreAccount;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import static java.util.logging.Logger.getLogger;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class RestoreAccountViewModel extends AndroidViewModel {
enum State {SET_PASSWORD, DOZE, CREATED, FAILED}
private static final Logger LOG =
getLogger(RestoreAccountViewModel.class.getName());
@Nullable
private String password;
private final MutableLiveEvent<State>
state = new MutableLiveEvent<>();
private final MutableLiveData<Boolean> isCreatingAccount =
new MutableLiveData<>(false);
private final AccountManager accountManager;
private final Executor ioExecutor;
private final PasswordStrengthEstimator strengthEstimator;
private final DozeHelper dozeHelper;
private final RestoreAccount restoreAccount;
@Inject
RestoreAccountViewModel(Application app,
AccountManager accountManager,
RestoreAccount restoreAccount,
@IoExecutor Executor ioExecutor,
PasswordStrengthEstimator strengthEstimator,
DozeHelper dozeHelper) {
super(app);
this.accountManager = accountManager;
this.ioExecutor = ioExecutor;
this.strengthEstimator = strengthEstimator;
this.dozeHelper = dozeHelper;
this.restoreAccount = restoreAccount;
ioExecutor.execute(() -> {
if (accountManager.accountExists()) {
throw new AssertionError();
} else {
state.postEvent(State.SET_PASSWORD);
}
});
}
LiveEvent<State> getState() {
return state;
}
LiveData<Boolean> getIsCreatingAccount() {
return isCreatingAccount;
}
// void setAuthorName(String authorName) {
// this.authorName = authorName;
// state.setEvent(SET_PASSWORD);
// }
void setPassword(String password) {
this.password = password;
if (needToShowDozeFragment()) {
state.setEvent(State.DOZE);
} else {
createAccount();
}
}
float estimatePasswordStrength(String password) {
return strengthEstimator.estimateStrength(password);
}
boolean needToShowDozeFragment() {
return dozeHelper.needToShowDozeFragment(getApplication());
}
void dozeExceptionConfirmed() {
createAccount();
}
private void createAccount() {
// if (authorName == null) throw new IllegalStateException();
if (password == null) throw new IllegalStateException();
isCreatingAccount.setValue(true);
Identity identity = restoreAccount.getSocialBackup().getIdentity();
ioExecutor.execute(() -> {
if (accountManager.restoreAccount(identity, password)) {
LOG.info("Restore account");
state.postEvent(State.CREATED);
} else {
LOG.warning("Failed to create account");
state.postEvent(State.FAILED);
}
});
}
}