mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Restore account activity/view model
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user