From 5b7bc54e1664b56c45f541aa35d30fdfe9bb31f4 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 9 Apr 2021 14:46:45 +0100 Subject: [PATCH 01/48] Add interfaces for social backup recovery tasks. --- .../socialbackup/recovery/CustodianTask.java | 51 ++++++++++++++++++ .../recovery/SecretOwnerTask.java | 53 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/CustodianTask.java create mode 100644 briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java diff --git a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/CustodianTask.java b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/CustodianTask.java new file mode 100644 index 000000000..2cb34c0d6 --- /dev/null +++ b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/CustodianTask.java @@ -0,0 +1,51 @@ +package org.briarproject.briar.api.socialbackup.recovery; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +@NotNullByDefault +public interface CustodianTask { + + void start(Observer observer); + + void cancel(); + + interface Observer { + void onStateChanged(State state); + } + + class State { + + static class Connecting extends State { + } + + static class SendingShard extends State { + } + + static class ReceivingAck extends State { + } + + static class Success extends State { + } + + static class Failure extends State { + + enum Reason { + QR_CODE_INVALID, + QR_CODE_TOO_OLD, + QR_CODE_TOO_NEW, + NO_CONNECTION, + OTHER + } + + private final Reason reason; + + Failure(Reason reason) { + this.reason = reason; + } + + public Reason getReason() { + return reason; + } + } + } +} diff --git a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java new file mode 100644 index 000000000..1f80cb156 --- /dev/null +++ b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java @@ -0,0 +1,53 @@ +package org.briarproject.briar.api.socialbackup.recovery; + +import org.briarproject.bramble.api.crypto.PublicKey; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.net.InetSocketAddress; + +@NotNullByDefault +public interface SecretOwnerTask { + + void start(Observer observer); + + void cancel(); + + interface Observer { + void onStateChanged(State state); + } + + class State { + + static class Listening extends State { + + private final PublicKey publicKey; + private final InetSocketAddress socketAddress; + + public Listening(PublicKey publicKey, + InetSocketAddress socketAddress) { + this.publicKey = publicKey; + this.socketAddress = socketAddress; + } + + public PublicKey getPublicKey() { + return publicKey; + } + + public InetSocketAddress getSocketAddress() { + return socketAddress; + } + } + + static class ReceivingShard extends State { + } + + static class SendingAck extends State { + } + + static class Success extends State { + } + + static class Failure extends State { + } + } +} From ea4bd5f438ae8941d34982b25606e1a05375ef5e Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 9 Apr 2021 15:58:50 +0200 Subject: [PATCH 02/48] WIP activity for custodian to return a shard --- .../recover/CustodianSendShardActivity.java | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianSendShardActivity.java diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianSendShardActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianSendShardActivity.java new file mode 100644 index 000000000..dd0eb19be --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianSendShardActivity.java @@ -0,0 +1,70 @@ +package org.briarproject.briar.android.socialbackup.recover; + +import android.os.Bundle; +import android.widget.Toast; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.briar.R; +import org.briarproject.briar.android.activity.ActivityComponent; +import org.briarproject.briar.android.activity.BriarActivity; +import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactPermissionManager; +import org.briarproject.briar.android.socialbackup.OwnerRecoveryModeMainFragment; +import org.briarproject.briar.api.socialbackup.ReturnShardPayload; + +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import androidx.lifecycle.ViewModelProvider; + +import static java.util.logging.Logger.getLogger; +import static org.briarproject.briar.android.socialbackup.CustodianHelpRecoverActivity.RETURN_SHARD_PAYLOAD; + +public class CustodianSendShardActivity extends BriarActivity { + private CustodianSendShardViewModel viewModel; + + private static final Logger LOG = + getLogger(CustodianSendShardActivity.class.getName()); + + @Inject + ViewModelProvider.Factory viewModelFactory; + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + viewModel = new ViewModelProvider(this, viewModelFactory) + .get(CustodianSendViewModel.class); + } + + @Override + public void onCreate(@Nullable Bundle state) { + super.onCreate(state); + + byte[] returnShardPayloadBytes = + getIntent().getByteArrayExtra(RETURN_SHARD_PAYLOAD); + try { + ReturnShardPayload returnShardPayload = parseReturnShardPayload( + clientHelper.toList(returnShardPayloadBytes)); +// viewModel.setReturnShardPayload(returnShardPayload); + } catch (FormatException e) { + Toast.makeText(this, + "Error reading social backup", + Toast.LENGTH_SHORT).show(); + finish(); + } + setContentView(R.layout.activity_fragment_container); + if (state == null) { + showInitialFragment(new OwnerRecoveryModeExplainerFragment()); + } + viewModel.getCheckPermissions().observeEvent(this, check -> + permissionManager.checkPermissions()); + viewModel.getRequestBluetoothDiscoverable().observeEvent(this, r -> + requestBluetoothDiscoverable()); // never false + viewModel.getShowQrCodeFragment().observeEvent(this, show -> { + if (show) showQrCodeFragment(); + }); + viewModel.getState() + .observe(this, this::onReturnShardStateChanged); + } +} From 9e4ace4ce7d26652ef161e10bc26f6aa1b240ce4 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 12 Apr 2021 10:50:47 +0200 Subject: [PATCH 03/48] Activity and view model for custodian returning shard --- .../android/activity/ActivityComponent.java | 10 +- ...ustodianRecoveryModeExplainerFragment.java | 41 ++-- .../recover/CustodianReturnShardActivity.java | 79 ++++++++ .../recover/CustodianReturnShardFragment.java | 185 ++++++++++++++++++ .../CustodianReturnShardViewModel.java | 110 +++++++++++ .../recover/CustodianSendShardActivity.java | 70 ------- .../OwnerRecoveryModeExplainerFragment.java | 1 - .../recovery/CustodianTaskImpl.java | 4 + 8 files changed, 412 insertions(+), 88 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardFragment.java create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java delete mode 100644 briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianSendShardActivity.java create mode 100644 briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java index 92b6c95e2..91a288110 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java @@ -80,11 +80,13 @@ import org.briarproject.briar.android.sharing.ShareBlogFragment; import org.briarproject.briar.android.sharing.ShareForumActivity; import org.briarproject.briar.android.sharing.ShareForumFragment; import org.briarproject.briar.android.sharing.SharingModule; -//import org.briarproject.briar.android.socialbackup.CustodianDisplayFragment; import org.briarproject.briar.android.socialbackup.CustodianHelpRecoverActivity; +import org.briarproject.briar.android.socialbackup.CustodianRecoveryModeExplainerFragment; import org.briarproject.briar.android.socialbackup.CustodianSelectorFragment; import org.briarproject.briar.android.socialbackup.DistributedBackupActivity; import org.briarproject.briar.android.socialbackup.ExistingBackupFragment; +import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardActivity; +import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardFragment; import org.briarproject.briar.android.socialbackup.recover.OwnerRecoveryModeExplainerFragment; import org.briarproject.briar.android.socialbackup.recover.RecoverActivity; import org.briarproject.briar.android.socialbackup.ShardsSentFragment; @@ -202,6 +204,8 @@ public interface ActivityComponent { void inject(ReturnShardActivity returnShardActivity); + void inject(CustodianReturnShardActivity custodianSendShardActivity); + // Fragments void inject(AuthorNameFragment fragment); @@ -279,4 +283,8 @@ public interface ActivityComponent { void inject(NewOrRecoverFragment newOrRecoverFragment); void inject(ReturnShardFragment returnShardFragment); + + void inject(CustodianRecoveryModeExplainerFragment custodianRecoveryModeExplainerFragment); + + void inject(CustodianReturnShardFragment custodianReturnShardFragment); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/CustodianRecoveryModeExplainerFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/CustodianRecoveryModeExplainerFragment.java index 50660fc99..c682c1d96 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/CustodianRecoveryModeExplainerFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/CustodianRecoveryModeExplainerFragment.java @@ -1,48 +1,57 @@ package org.briarproject.briar.android.socialbackup; -import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import org.briarproject.briar.R; +import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.fragment.BaseFragment; +import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardViewModel; + +import javax.inject.Inject; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import org.briarproject.briar.R; +import androidx.lifecycle.ViewModelProvider; public class CustodianRecoveryModeExplainerFragment extends BaseFragment { - protected CustodianScanQrButtonListener listener; + @Inject + ViewModelProvider.Factory viewModelFactory; - public static final String TAG = CustodianRecoveryModeExplainerFragment.class.getName(); + private CustodianReturnShardViewModel viewModel; + + public static final String TAG = + CustodianRecoveryModeExplainerFragment.class.getName(); @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - requireActivity().setTitle(R.string.title_help_recover); + public void injectFragment(ActivityComponent component) { + component.inject(this); + viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) + .get(CustodianReturnShardViewModel.class); } +// @Override +// public void onCreate(@Nullable Bundle savedInstanceState) { +// super.onCreate(savedInstanceState); +// requireActivity().setTitle(R.string.title_help_recover); +// } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_recovery_custodian_explainer, - container, false); + View view = + inflater.inflate(R.layout.fragment_recovery_custodian_explainer, + container, false); Button button = view.findViewById(R.id.button); - button.setOnClickListener(e -> listener.scanQrButtonClicked()); + button.setOnClickListener(e -> viewModel.onContinueClicked()); return view; } - @Override - public void onAttach(Context context) { - super.onAttach(context); - listener = (CustodianScanQrButtonListener) context; - } - @Override public String getUniqueTag() { return TAG; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java new file mode 100644 index 000000000..43b7ccb02 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java @@ -0,0 +1,79 @@ +package org.briarproject.briar.android.socialbackup.recover; + +import android.os.Bundle; + +import org.briarproject.briar.R; +import org.briarproject.briar.android.activity.ActivityComponent; +import org.briarproject.briar.android.activity.BriarActivity; +import org.briarproject.briar.android.fragment.BaseFragment; +import org.briarproject.briar.android.socialbackup.CustodianRecoveryModeExplainerFragment; + +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import androidx.fragment.app.FragmentManager; +import androidx.lifecycle.ViewModelProvider; + +import static java.util.logging.Logger.getLogger; + +public class CustodianReturnShardActivity extends BriarActivity { + private CustodianReturnShardViewModel viewModel; + + private static final Logger LOG = + getLogger(CustodianReturnShardActivity.class.getName()); + + @Inject + ViewModelProvider.Factory viewModelFactory; + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + viewModel = new ViewModelProvider(this, viewModelFactory) + .get(CustodianReturnShardViewModel.class); + } + + @Override + public void onCreate(@Nullable Bundle state) { + super.onCreate(state); + +// byte[] returnShardPayloadBytes = +// getIntent().getByteArrayExtra(RETURN_SHARD_PAYLOAD); +// try { +// ReturnShardPayload returnShardPayload = parseReturnShardPayload( +// clientHelper.toList(returnShardPayloadBytes)); +// viewModel.setReturnShardPayload(returnShardPayload); +// } catch (FormatException e) { +// Toast.makeText(this, +// "Error reading social backup", +// Toast.LENGTH_SHORT).show(); +// finish(); +// } + setContentView(R.layout.activity_fragment_container); + if (state == null) { + showInitialFragment(new CustodianRecoveryModeExplainerFragment()); + } +// viewModel.getCheckPermissions().observeEvent(this, check -> +// permissionManager.checkPermissions()); +// viewModel.getRequestBluetoothDiscoverable().observeEvent(this, r -> +// requestBluetoothDiscoverable()); // never false + viewModel.getShowCameraFragment().observeEvent(this, show -> { + if (show) showCameraFragment(); + }); +// viewModel.getState() +// .observe(this, this::onReturnShardStateChanged); + } + + private void showCameraFragment() { + // FIXME #824 + FragmentManager fm = getSupportFragmentManager(); + if (fm.findFragmentByTag(CustodianReturnShardFragment.TAG) == null) { + BaseFragment f = CustodianReturnShardFragment.newInstance(); + fm.beginTransaction() + .replace(R.id.fragmentContainer, f, f.getUniqueTag()) + .addToBackStack(f.getUniqueTag()) + .commit(); + } + } +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardFragment.java new file mode 100644 index 000000000..220eeba31 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardFragment.java @@ -0,0 +1,185 @@ +package org.briarproject.briar.android.socialbackup.recover; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.briar.R; +import org.briarproject.briar.android.activity.ActivityComponent; +import org.briarproject.briar.android.contact.add.nearby.CameraException; +import org.briarproject.briar.android.contact.add.nearby.CameraView; +import org.briarproject.briar.android.fragment.BaseFragment; +import org.briarproject.briar.android.view.QrCodeView; +import org.briarproject.briar.api.socialbackup.recovery.CustodianTask; + +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import androidx.annotation.UiThread; +import androidx.lifecycle.ViewModelProvider; + +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.widget.LinearLayout.HORIZONTAL; +import static android.widget.Toast.LENGTH_LONG; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class CustodianReturnShardFragment extends BaseFragment + implements QrCodeView.FullscreenListener { + + public static final String TAG = CustodianReturnShardFragment.class.getName(); + + private static final Logger LOG = Logger.getLogger(TAG); + + @Inject + ViewModelProvider.Factory viewModelFactory; + + private CustodianReturnShardViewModel viewModel; + private CameraView cameraView; + private LinearLayout cameraOverlay; + private View statusView; + private TextView status; + + public static CustodianReturnShardFragment newInstance() { + Bundle args = new Bundle(); + CustodianReturnShardFragment fragment = new CustodianReturnShardFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) + .get(CustodianReturnShardViewModel.class); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_keyagreement_qr, container, + false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + cameraView = view.findViewById(R.id.camera_view); + cameraOverlay = view.findViewById(R.id.camera_overlay); + statusView = view.findViewById(R.id.status_container); + status = view.findViewById(R.id.connect_status); + + viewModel.getState().observe(getViewLifecycleOwner(), + this::onReturnShardStateChanged); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + requireActivity().setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR); + cameraView.setPreviewConsumer(viewModel.getQrCodeDecoder()); + } + + @Override + public void onStart() { + super.onStart(); + try { + cameraView.start(); + } catch (CameraException e) { + logCameraExceptionAndFinish(e); + } + } + + @Override + public void onStop() { + super.onStop(); + try { + cameraView.stop(); + } catch (CameraException e) { + logCameraExceptionAndFinish(e); + } + } + + @Override + public void onDestroy() { + requireActivity() + .setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED); + super.onDestroy(); + } + + @Override + public void setFullscreen(boolean fullscreen) { + LinearLayout.LayoutParams statusParams, qrCodeParams; + if (fullscreen) { + statusParams = new LinearLayout.LayoutParams(0, 0, 0f); + } else { + if (cameraOverlay.getOrientation() == HORIZONTAL) { + statusParams = new LinearLayout.LayoutParams(0, MATCH_PARENT, 1f); + } else { + statusParams = new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1f); + } + } + statusView.setLayoutParams(statusParams); + cameraOverlay.invalidate(); + } + + @UiThread + private void onReturnShardStateChanged(@Nullable CustodianTask.State state) { + if (state instanceof CustodianTask.State.Connecting) { + try { + cameraView.stop(); + } catch (CameraException e) { + logCameraExceptionAndFinish(e); + } + cameraView.setVisibility(INVISIBLE); + statusView.setVisibility(VISIBLE); + status.setText(R.string.connecting_to_device); + } else if (state instanceof CustodianTask.State.SendingShard) { + status.setText("Sending shard"); + } else if (state instanceof CustodianTask.State.ReceivingAck) { + status.setText("Receiving Ack"); + } else if (state instanceof CustodianTask.State.Success) { + // TODO + status.setText(R.string.exchanging_contact_details); + } else if (state instanceof CustodianTask.State.Failure) { + // the activity will replace this fragment with an error fragment + statusView.setVisibility(INVISIBLE); + cameraView.setVisibility(INVISIBLE); + } + } + + @Override + public String getUniqueTag() { + return TAG; + } + + @UiThread + private void logCameraExceptionAndFinish(CameraException e) { + logException(LOG, WARNING, e); + Toast.makeText(getActivity(), R.string.camera_error, + LENGTH_LONG).show(); + finish(); + } + + @Override + protected void finish() { + requireActivity().getSupportFragmentManager().popBackStack(); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java new file mode 100644 index 000000000..b454ca859 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java @@ -0,0 +1,110 @@ +package org.briarproject.briar.android.socialbackup.recover; + +import android.app.Application; +import android.widget.Toast; + +import com.google.zxing.Result; + +import org.briarproject.bramble.api.UnsupportedVersionException; +import org.briarproject.bramble.api.keyagreement.Payload; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.system.AndroidExecutor; +import org.briarproject.briar.R; +import org.briarproject.briar.android.contact.add.nearby.QrCodeDecoder; +import org.briarproject.briar.android.viewmodel.LiveEvent; +import org.briarproject.briar.android.viewmodel.MutableLiveEvent; +import org.briarproject.briar.api.socialbackup.recovery.CustodianTask; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.security.cert.CertPathValidatorException; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import androidx.annotation.NonNull; +import androidx.annotation.UiThread; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import static android.widget.Toast.LENGTH_LONG; +import static java.util.Objects.requireNonNull; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; + +public class CustodianReturnShardViewModel extends AndroidViewModel + implements QrCodeDecoder.ResultCallback { + + private static final Logger LOG = + getLogger(CustodianReturnShardViewModel.class.getName()); + + private final AndroidExecutor androidExecutor; + private final Executor ioExecutor; + private boolean wasContinueClicked = false; + private final MutableLiveEvent showCameraFragment = + new MutableLiveEvent<>(); + private final MutableLiveData state = + new MutableLiveData<>(); + final QrCodeDecoder qrCodeDecoder; + + @SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19 + private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); + + @Inject + public CustodianReturnShardViewModel( + @NonNull Application application, + @IoExecutor Executor ioExecutor, + AndroidExecutor androidExecutor) { + super(application); + + this.androidExecutor = androidExecutor; + this.ioExecutor = ioExecutor; + qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this); + } + + @IoExecutor + @Override + public void onQrCodeDecoded(Result result) { + LOG.info("Got result from decoder"); + // Ignore results until the KeyAgreementTask is ready +// if (!gotLocalPayload || gotRemotePayload) return; + try { + byte[] payloadBytes = result.getText().getBytes(ISO_8859_1); + if (LOG.isLoggable(INFO)) + LOG.info("Remote payload is " + payloadBytes.length + " bytes"); +// Payload remotePayload = payloadParser.parse(payloadBytes); +// gotRemotePayload = true; +// requireNonNull(task).connectAndRunProtocol(remotePayload); +// state.postValue(new ReturnShardState.QrCodeScanned()); + } catch (IllegalArgumentException e) { + LOG.log(WARNING, "QR Code Invalid", e); + androidExecutor.runOnUiThread(() -> Toast.makeText(getApplication(), + R.string.qr_code_invalid, LENGTH_LONG).show()); +// resetPayloadFlags(); + state.postValue(new CustodianTask.State.Failure( + CustodianTask.State.Failure.Reason.QR_CODE_INVALID)); + } + } + + @UiThread + public void onContinueClicked() { + wasContinueClicked = true; +// checkPermissions.setEvent(true); + showCameraFragment.setEvent(true); + } + + QrCodeDecoder getQrCodeDecoder() { + return qrCodeDecoder; + } + + LiveEvent getShowCameraFragment() { + return showCameraFragment; + } + + LiveData getState() { + return state; + } +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianSendShardActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianSendShardActivity.java deleted file mode 100644 index dd0eb19be..000000000 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianSendShardActivity.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.briarproject.briar.android.socialbackup.recover; - -import android.os.Bundle; -import android.widget.Toast; - -import org.briarproject.bramble.api.FormatException; -import org.briarproject.briar.R; -import org.briarproject.briar.android.activity.ActivityComponent; -import org.briarproject.briar.android.activity.BriarActivity; -import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactPermissionManager; -import org.briarproject.briar.android.socialbackup.OwnerRecoveryModeMainFragment; -import org.briarproject.briar.api.socialbackup.ReturnShardPayload; - -import java.util.logging.Logger; - -import javax.annotation.Nullable; -import javax.inject.Inject; - -import androidx.lifecycle.ViewModelProvider; - -import static java.util.logging.Logger.getLogger; -import static org.briarproject.briar.android.socialbackup.CustodianHelpRecoverActivity.RETURN_SHARD_PAYLOAD; - -public class CustodianSendShardActivity extends BriarActivity { - private CustodianSendShardViewModel viewModel; - - private static final Logger LOG = - getLogger(CustodianSendShardActivity.class.getName()); - - @Inject - ViewModelProvider.Factory viewModelFactory; - - @Override - public void injectActivity(ActivityComponent component) { - component.inject(this); - viewModel = new ViewModelProvider(this, viewModelFactory) - .get(CustodianSendViewModel.class); - } - - @Override - public void onCreate(@Nullable Bundle state) { - super.onCreate(state); - - byte[] returnShardPayloadBytes = - getIntent().getByteArrayExtra(RETURN_SHARD_PAYLOAD); - try { - ReturnShardPayload returnShardPayload = parseReturnShardPayload( - clientHelper.toList(returnShardPayloadBytes)); -// viewModel.setReturnShardPayload(returnShardPayload); - } catch (FormatException e) { - Toast.makeText(this, - "Error reading social backup", - Toast.LENGTH_SHORT).show(); - finish(); - } - setContentView(R.layout.activity_fragment_container); - if (state == null) { - showInitialFragment(new OwnerRecoveryModeExplainerFragment()); - } - viewModel.getCheckPermissions().observeEvent(this, check -> - permissionManager.checkPermissions()); - viewModel.getRequestBluetoothDiscoverable().observeEvent(this, r -> - requestBluetoothDiscoverable()); // never false - viewModel.getShowQrCodeFragment().observeEvent(this, show -> { - if (show) showQrCodeFragment(); - }); - viewModel.getState() - .observe(this, this::onReturnShardStateChanged); - } -} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerRecoveryModeExplainerFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerRecoveryModeExplainerFragment.java index 92e38aaff..370cb71c8 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerRecoveryModeExplainerFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerRecoveryModeExplainerFragment.java @@ -47,7 +47,6 @@ public class OwnerRecoveryModeExplainerFragment extends BaseFragment { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - System.out.println("GOt here *************************************"); View view = inflater.inflate(R.layout.fragment_recovery_owner_explainer, container, false); Button button = view.findViewById(R.id.beginButton); diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java new file mode 100644 index 000000000..197b1f015 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java @@ -0,0 +1,4 @@ +package org.briarproject.briar.socialbackup.recovery; + +public class CustodianTaskImpl { +} From 207a8bc7cb377086990e6cc5973d3fa8fb644aa8 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 12 Apr 2021 10:51:34 +0200 Subject: [PATCH 04/48] make CustodianTask states public --- .../api/socialbackup/recovery/CustodianTask.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/CustodianTask.java b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/CustodianTask.java index 2cb34c0d6..91bc9060b 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/CustodianTask.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/CustodianTask.java @@ -15,21 +15,21 @@ public interface CustodianTask { class State { - static class Connecting extends State { + public static class Connecting extends State { } - static class SendingShard extends State { + public static class SendingShard extends State { } - static class ReceivingAck extends State { + public static class ReceivingAck extends State { } - static class Success extends State { + public static class Success extends State { } - static class Failure extends State { + public static class Failure extends State { - enum Reason { + public enum Reason { QR_CODE_INVALID, QR_CODE_TOO_OLD, QR_CODE_TOO_NEW, @@ -39,7 +39,7 @@ public interface CustodianTask { private final Reason reason; - Failure(Reason reason) { + public Failure(Reason reason) { this.reason = reason; } From 71b8c32a3efff66090f366f687974ac309789d87 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 12 Apr 2021 10:52:03 +0200 Subject: [PATCH 05/48] implement CustodianTask --- .../socialbackup/recovery/CustodianTaskImpl.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java index 197b1f015..af89bde8b 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java @@ -1,4 +1,15 @@ package org.briarproject.briar.socialbackup.recovery; -public class CustodianTaskImpl { +import org.briarproject.briar.api.socialbackup.recovery.CustodianTask; + +public class CustodianTaskImpl implements CustodianTask { + @Override + public void start(Observer observer) { + + } + + @Override + public void cancel() { + + } } From 9d01de9868270d2efa49240e495605ddafb7acff Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 12 Apr 2021 12:21:16 +0200 Subject: [PATCH 06/48] Secret owner return shard - activity, view model and fragment --- .../android/activity/ActivityComponent.java | 3 + .../recover/OwnerReturnShardActivity.java | 192 ++++++++++++++ .../recover/OwnerReturnShardFragment.java | 158 ++++++++++++ .../recover/OwnerReturnShardViewModel.java | 236 ++++++++++++++++++ 4 files changed, 589 insertions(+) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java index 91a288110..eb409419c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java @@ -88,6 +88,7 @@ import org.briarproject.briar.android.socialbackup.ExistingBackupFragment; import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardActivity; import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardFragment; import org.briarproject.briar.android.socialbackup.recover.OwnerRecoveryModeExplainerFragment; +import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardFragment; import org.briarproject.briar.android.socialbackup.recover.RecoverActivity; import org.briarproject.briar.android.socialbackup.ShardsSentFragment; import org.briarproject.briar.android.socialbackup.ThresholdSelectorFragment; @@ -287,4 +288,6 @@ public interface ActivityComponent { void inject(CustodianRecoveryModeExplainerFragment custodianRecoveryModeExplainerFragment); void inject(CustodianReturnShardFragment custodianReturnShardFragment); + + void inject(OwnerReturnShardFragment ownerReturnShardFragment); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java new file mode 100644 index 000000000..c2982f698 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java @@ -0,0 +1,192 @@ +package org.briarproject.briar.android.socialbackup.recover; + +import android.content.Intent; +import android.os.Bundle; +import android.view.MenuItem; +import android.widget.Toast; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.briar.R; +import org.briarproject.briar.android.activity.ActivityComponent; +import org.briarproject.briar.android.activity.BaseActivity; +import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactErrorFragment; +import org.briarproject.briar.android.fragment.BaseFragment; +import org.briarproject.briar.android.util.RequestBluetoothDiscoverable; + +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.fragment.app.FragmentManager; +import androidx.lifecycle.ViewModelProvider; + +import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; +import static android.widget.Toast.LENGTH_LONG; +import static java.util.logging.Logger.getLogger; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class OwnerReturnShardActivity extends BaseActivity + implements BaseFragment.BaseFragmentListener { + + private static final Logger LOG = + getLogger(OwnerReturnShardActivity.class.getName()); + + @Inject + ViewModelProvider.Factory viewModelFactory; + + private OwnerReturnShardViewModel viewModel; + +// private final ActivityResultLauncher permissionLauncher = +// registerForActivityResult( +// new ActivityResultContracts.RequestMultiplePermissions(), +// r -> +// permissionManager.onRequestPermissionResult(r, +// viewModel::showQrCodeFragmentIfAllowed)); + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + viewModel = new ViewModelProvider(this, viewModelFactory) + .get(OwnerReturnShardViewModel.class); + } + + // TODO the following two methods should be injected from messageParser +// private Shard parseShardMessage(BdfList body) throws FormatException { +// // Message type, secret ID, shard +// byte[] secretId = body.getRaw(1); +// byte[] shard = body.getRaw(2); +// return new Shard(secretId, shard); +// } +// +// private ReturnShardPayload parseReturnShardPayload(BdfList body) +// throws FormatException { +// checkSize(body, 2); +// Shard shard = parseShardMessage(body.getList(0)); +// org.briarproject.briar.api.socialbackup.BackupPayload backupPayload = +// new BackupPayload(body.getRaw(1)); +// return new ReturnShardPayload(shard, backupPayload); +// } + + @Override + public void onCreate(@Nullable Bundle state) { + super.onCreate(state); + + setContentView(R.layout.activity_fragment_container); + if (state == null) { + showInitialFragment(new OwnerRecoveryModeExplainerFragment()); + } +// viewModel.getCheckPermissions().observeEvent(this, check -> +// permissionManager.checkPermissions()); +// viewModel.getRequestBluetoothDiscoverable().observeEvent(this, r -> +// requestBluetoothDiscoverable()); // never false + viewModel.getShowQrCodeFragment().observeEvent(this, show -> { + if (show) showQrCodeFragment(); + }); +// viewModel.getState() +// .observe(this, this::onReturnShardStateChanged); + } + + @Override + public void onStart() { + super.onStart(); + } + + @Override + protected void onPostResume() { + super.onPostResume(); +// viewModel.setIsActivityResumed(true); + } + + @Override + protected void onPause() { + super.onPause(); +// viewModel.setIsActivityResumed(false); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onBackPressed() { + if (viewModel.getState() + .getValue() instanceof ReturnShardState.Failed) { + // re-create this activity when going back in failed state + Intent i = new Intent(this, ReturnShardActivity.class); + i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); + startActivity(i); + } else { + super.onBackPressed(); + } + } + + private void showQrCodeFragment() { + FragmentManager fm = getSupportFragmentManager(); + if (fm.findFragmentByTag(OwnerReturnShardFragment.TAG) == null) { + BaseFragment f = OwnerReturnShardFragment.newInstance(); + fm.beginTransaction() + .replace(R.id.fragmentContainer, f, f.getUniqueTag()) + .addToBackStack(f.getUniqueTag()) + .commit(); + } + } + + private void onReturnShardStateChanged(ReturnShardState state) { + if (state instanceof ReturnShardState.SocialBackupExchangeFinished) { + ReturnShardState.SocialBackupExchangeResult result = + ((ReturnShardState.SocialBackupExchangeFinished) state).result; + onSocialBackupExchangeResult(result); + } else if (state instanceof ReturnShardState.Failed) { + Boolean qrCodeTooOld = + ((ReturnShardState.Failed) state).qrCodeTooOld; + onAddingContactFailed(qrCodeTooOld); + } + } + + private void onSocialBackupExchangeResult( + ReturnShardState.SocialBackupExchangeResult result) { + if (result instanceof ReturnShardState.SocialBackupExchangeResult.Success) { +// String text = getString(R.string.contact_added_toast, contactName); + Toast.makeText(this, "Shard return successful", LENGTH_LONG).show(); + supportFinishAfterTransition(); + } else if (result instanceof ReturnShardState.SocialBackupExchangeResult.Error) { + showErrorFragment(); + } else throw new AssertionError(); + } + + private void onAddingContactFailed(@Nullable Boolean qrCodeTooOld) { + if (qrCodeTooOld == null) { + showErrorFragment(); + } else { + String msg; + if (qrCodeTooOld) { + msg = getString(R.string.qr_code_too_old, + getString(R.string.app_name)); + } else { + msg = getString(R.string.qr_code_too_new, + getString(R.string.app_name)); + } + showNextFragment(AddNearbyContactErrorFragment.newInstance(msg)); + } + } + + private void showErrorFragment() { + showNextFragment(new AddNearbyContactErrorFragment()); + } + + @Override + @Deprecated + public void runOnDbThread(Runnable runnable) { + throw new RuntimeException("Don't use this deprecated method here."); + } +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java new file mode 100644 index 000000000..8582466d9 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java @@ -0,0 +1,158 @@ +package org.briarproject.briar.android.socialbackup.recover; + +import android.graphics.Bitmap; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.briar.R; +import org.briarproject.briar.android.activity.ActivityComponent; +import org.briarproject.briar.android.contact.add.nearby.CameraException; +import org.briarproject.briar.android.contact.add.nearby.CameraView; +import org.briarproject.briar.android.fragment.BaseFragment; +import org.briarproject.briar.android.view.QrCodeView; +import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; + +import java.util.logging.Logger; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import androidx.annotation.UiThread; +import androidx.lifecycle.ViewModelProvider; + +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.widget.LinearLayout.HORIZONTAL; +import static android.widget.Toast.LENGTH_LONG; +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.util.LogUtils.logException; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class OwnerReturnShardFragment extends BaseFragment + implements QrCodeView.FullscreenListener { + + public static final String TAG = OwnerReturnShardFragment.class.getName(); + + private static final Logger LOG = Logger.getLogger(TAG); + + @Inject + ViewModelProvider.Factory viewModelFactory; + + private OwnerReturnShardViewModel viewModel; + private LinearLayout cameraOverlay; + private View statusView; + private QrCodeView qrCodeView; + private TextView status; + + public static OwnerReturnShardFragment newInstance() { + Bundle args = new Bundle(); + OwnerReturnShardFragment fragment = new OwnerReturnShardFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) + .get(OwnerReturnShardViewModel.class); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_keyagreement_qr, container, + false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + cameraOverlay = view.findViewById(R.id.camera_overlay); + statusView = view.findViewById(R.id.status_container); + status = view.findViewById(R.id.connect_status); + qrCodeView = view.findViewById(R.id.qr_code_view); + qrCodeView.setFullscreenListener(this); + + viewModel.getState().observe(getViewLifecycleOwner(), + this::onReturnShardStateChanged); + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + requireActivity().setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR); + } + + @Override + public void onDestroy() { + requireActivity() + .setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED); + super.onDestroy(); + } + + @Override + public void setFullscreen(boolean fullscreen) { + LinearLayout.LayoutParams statusParams, qrCodeParams; + if (fullscreen) { + // Grow the QR code view to fill its parent + statusParams = new LinearLayout.LayoutParams(0, 0, 0f); + qrCodeParams = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT, 1f); + } else { + // Shrink the QR code view to fill half its parent + if (cameraOverlay.getOrientation() == HORIZONTAL) { + statusParams = new LinearLayout.LayoutParams(0, MATCH_PARENT, 1f); + qrCodeParams = new LinearLayout.LayoutParams(0, MATCH_PARENT, 1f); + } else { + statusParams = new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1f); + qrCodeParams = new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1f); + } + } + statusView.setLayoutParams(statusParams); + qrCodeView.setLayoutParams(qrCodeParams); + cameraOverlay.invalidate(); + } + + @UiThread + private void onReturnShardStateChanged(@Nullable SecretOwnerTask.State state) { + if (state instanceof SecretOwnerTask.State.Listening) { + Bitmap qrCode = + ((ReturnShardState.KeyAgreementListening) state).qrCode; + qrCodeView.setQrCode(qrCode); + } else if (state instanceof SecretOwnerTask.State.ReceivingShard) { + statusView.setVisibility(VISIBLE); + status.setText(R.string.connecting_to_device); + } else if (state instanceof SecretOwnerTask.State.SendingAck) { + status.setText(R.string.waiting_for_contact_to_scan); + } else if (state instanceof SecretOwnerTask.State.Success) { + status.setText("Success"); + } else if (state instanceof SecretOwnerTask.State.Failure) { + // the activity will replace this fragment with an error fragment + statusView.setVisibility(INVISIBLE); + } + } + + @Override + public String getUniqueTag() { + return TAG; + } + + @Override + protected void finish() { + requireActivity().getSupportFragmentManager().popBackStack(); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java new file mode 100644 index 000000000..a4bb76a43 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java @@ -0,0 +1,236 @@ +package org.briarproject.briar.android.socialbackup.recover; + +import android.app.Application; +import android.graphics.Bitmap; +import android.util.DisplayMetrics; + +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.db.ContactExistsException; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.keyagreement.KeyAgreementResult; +import org.briarproject.bramble.api.keyagreement.Payload; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; +import org.briarproject.bramble.api.system.AndroidExecutor; +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.ReturnShardPayload; +import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.concurrent.Executor; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import androidx.annotation.UiThread; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; +import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.util.LogUtils.logException; + +@NotNullByDefault +class OwnerReturnShardViewModel extends AndroidViewModel { + + private static final Logger LOG = + getLogger(OwnerReturnShardViewModel.class.getName()); + + @SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19 + private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); + + private ReturnShardPayload returnShardPayload; + + private final AndroidExecutor androidExecutor; + private final Executor ioExecutor; + + private final MutableLiveEvent showQrCodeFragment = + new MutableLiveEvent<>(); + private final MutableLiveData state = + new MutableLiveData<>(); + + private boolean wasContinueClicked = false; + private boolean isActivityResumed = false; + + @Inject + OwnerReturnShardViewModel(Application app, + AndroidExecutor androidExecutor, + @IoExecutor Executor ioExecutor) { + super(app); + this.androidExecutor = androidExecutor; + this.ioExecutor = ioExecutor; +// IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED); + } + + @Override + protected void onCleared() { + super.onCleared(); + stopListening(); + } + + @UiThread + void onContinueClicked() { + wasContinueClicked = true; + startShardReturn(); + } + + @UiThread + void startShardReturn() { + // If we return to the intro fragment, the continue button needs to be + // clicked again before showing the QR code fragment + wasContinueClicked = false; + // If we return to the intro fragment, we may need to enable wifi and +// hasEnabledWifi = false; + startListening(); + showQrCodeFragment.setEvent(true); + } + + @UiThread + private void startListening() { +// KeyAgreementTask oldTask = task; +// KeyAgreementTask newTask = keyAgreementTaskProvider.get(); +// task = newTask; +// ioExecutor.execute(() -> { +// if (oldTask != null) oldTask.stopListening(); +// newTask.listen(); +// }); + } + + @UiThread + private void stopListening() { +// KeyAgreementTask oldTask = task; +// ioExecutor.execute(() -> { +// if (oldTask != null) oldTask.stopListening(); +// }); + } + +// @Override +// public void eventOccurred(Event e) { +// if (e instanceof TransportStateEvent) { +// TransportStateEvent t = (TransportStateEvent) e; +// if (t.getTransportId().equals(BluetoothConstants.ID)) { +// if (LOG.isLoggable(INFO)) { +// LOG.info("Bluetooth state changed to " + t.getState()); +// } +// showQrCodeFragmentIfAllowed(); +// } else if (t.getTransportId().equals(LanTcpConstants.ID)) { +// if (LOG.isLoggable(INFO)) { +// LOG.info("Wifi state changed to " + t.getState()); +// } +// showQrCodeFragmentIfAllowed(); +// } +// } else if (e instanceof KeyAgreementListeningEvent) { +// LOG.info("KeyAgreementListeningEvent received"); +// KeyAgreementListeningEvent event = (KeyAgreementListeningEvent) e; +// onLocalPayloadReceived(event.getLocalPayload()); +// } else if (e instanceof KeyAgreementWaitingEvent) { +// LOG.info("KeyAgreementWaitingEvent received"); +// state.setValue(new ReturnShardState.KeyAgreementWaiting()); +// } else if (e instanceof KeyAgreementStartedEvent) { +// LOG.info("KeyAgreementStartedEvent received"); +// state.setValue(new ReturnShardState.KeyAgreementStarted()); +// } else if (e instanceof KeyAgreementFinishedEvent) { +// LOG.info("KeyAgreementFinishedEvent received"); +// KeyAgreementResult result = +// ((KeyAgreementFinishedEvent) e).getResult(); +// startContactExchange(result); +// state.setValue(new ReturnShardState.SocialBackupExchangeStarted()); +// } else if (e instanceof KeyAgreementAbortedEvent) { +// LOG.info("KeyAgreementAbortedEvent received"); +// resetPayloadFlags(); +// state.setValue(new ReturnShardState.Failed()); +// } else if (e instanceof KeyAgreementFailedEvent) { +// LOG.info("KeyAgreementFailedEvent received"); +// resetPayloadFlags(); +// state.setValue(new ReturnShardState.Failed()); +// } +// } + + /** + * This sets the QR code by setting the state to KeyAgreementListening. + */ + private void onLocalPayloadReceived(Payload localPayload) { + if (gotLocalPayload) return; + DisplayMetrics dm = getApplication().getResources().getDisplayMetrics(); + ioExecutor.execute(() -> { + byte[] payloadBytes = payloadEncoder.encode(localPayload); + if (LOG.isLoggable(INFO)) { + LOG.info("Local payload is " + payloadBytes.length + + " bytes"); + } + // Use ISO 8859-1 to encode bytes directly as a string + String content = new String(payloadBytes, ISO_8859_1); + Bitmap qrCode = QrCodeUtils.createQrCode(dm, content); + gotLocalPayload = true; + state.postValue(new SecretOwnerTask.State.Listening(qrCode)); + }); + } + + @UiThread +// private void startContactExchange(KeyAgreementResult result) { +// TransportId t = result.getTransportId(); +// DuplexTransportConnection conn = result.getConnection(); +// SecretKey masterKey = result.getMasterKey(); +// boolean alice = result.wasAlice(); +// ioExecutor.execute(() -> { +// try { +// if (sending) { +// socialBackupExchangeManager.sendReturnShard(conn, masterKey, alice, returnShardPayload); +// } else { +// returnShardPayload = socialBackupExchangeManager.receiveReturnShard(conn, masterKey, alice); +// } +// ReturnShardState.SocialBackupExchangeResult.Success +// success = +// new ReturnShardState.SocialBackupExchangeResult.Success(); +// state.postValue( +// new ReturnShardState.SocialBackupExchangeFinished(success)); +// } catch (ContactExistsException e) { +// tryToClose(conn); +// ReturnShardState.SocialBackupExchangeResult.Error +// error = new ReturnShardState.SocialBackupExchangeResult.Error( +// e.getRemoteAuthor()); +// state.postValue( +// new ReturnShardState.SocialBackupExchangeFinished(error)); +// } catch (DbException | IOException e) { +// tryToClose(conn); +// logException(LOG, WARNING, e); +// ReturnShardState.SocialBackupExchangeResult.Error +// error = +// new ReturnShardState.SocialBackupExchangeResult.Error(null); +// state.postValue( +// new ReturnShardState.SocialBackupExchangeFinished(error)); +// } +// }); +// } + + + /** + * Set to true in onPostResume() and false in onPause(). This prevents the + * QR code fragment from being shown if onRequestPermissionsResult() is + * called while the activity is paused, which could cause a crash due to + * https://issuetracker.google.com/issues/37067655. + * TODO check if this is still happening with new permission requesting + */ + @UiThread + void setIsActivityResumed(boolean resumed) { + isActivityResumed = resumed; + // Workaround for + // https://code.google.com/p/android/issues/detail?id=190966 +// showQrCodeFragmentIfAllowed(); + } + + LiveEvent getShowQrCodeFragment() { + return showQrCodeFragment; + } + + LiveData getState() { + return state; + } +} From 30b2905c2e7ea86410ee867d82d32ce16fc77bf6 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 12 Apr 2021 12:21:35 +0200 Subject: [PATCH 07/48] make SecretOwnerTask states public --- .../api/socialbackup/recovery/SecretOwnerTask.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java index 1f80cb156..0278645d5 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java @@ -18,7 +18,7 @@ public interface SecretOwnerTask { class State { - static class Listening extends State { + public static class Listening extends State { private final PublicKey publicKey; private final InetSocketAddress socketAddress; @@ -38,16 +38,16 @@ public interface SecretOwnerTask { } } - static class ReceivingShard extends State { + public static class ReceivingShard extends State { } - static class SendingAck extends State { + public static class SendingAck extends State { } - static class Success extends State { + public static class Success extends State { } - static class Failure extends State { + public static class Failure extends State { } } } From 71c327112c78ae706f5cf56fd1dec32aee94dd78 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 12 Apr 2021 15:02:26 +0200 Subject: [PATCH 08/48] Implement SecretOwnerTask --- .../recovery/SecretOwnerTaskImpl.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java new file mode 100644 index 000000000..0a7439b59 --- /dev/null +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java @@ -0,0 +1,39 @@ +package org.briarproject.briar.socialbackup.recovery; + +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.crypto.KeyPair; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; + +import java.net.InetSocketAddress; +import java.util.concurrent.Executor; + +import javax.inject.Inject; + +public class SecretOwnerTaskImpl implements SecretOwnerTask { + + private final CryptoComponent crypto; + private final Executor ioExecutor; + private final KeyPair localKeyPair; + private boolean cancelled = false; + + @Inject + SecretOwnerTaskImpl(CryptoComponent crypto, + @IoExecutor Executor ioExecutor) { + this.crypto = crypto; + this.ioExecutor = ioExecutor; + localKeyPair = crypto.generateAgreementKeyPair(); + } + + @Override + public void start(Observer observer) { + // TODO use the actual ip address on local network + InetSocketAddress socketAddress = InetSocketAddress.createUnresolved("localhost", 1234); + observer.onStateChanged(new State.Listening(localKeyPair.getPublic(), socketAddress)); + } + + @Override + public void cancel() { + cancelled = true; + } +} From d925f3be0bde13bbf3c568da1d3c23e0bfef5f40 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 12 Apr 2021 15:03:15 +0200 Subject: [PATCH 09/48] Secret owner return shard - activity, view model and fragment - qr code generation --- .../android/activity/ActivityComponent.java | 5 +- .../recover/OwnerReturnShardActivity.java | 32 +++++---- .../recover/OwnerReturnShardFragment.java | 3 +- .../recover/OwnerReturnShardViewModel.java | 65 +++++++++---------- 4 files changed, 50 insertions(+), 55 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java index eb409419c..e4859d5c8 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java @@ -88,6 +88,7 @@ import org.briarproject.briar.android.socialbackup.ExistingBackupFragment; import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardActivity; import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardFragment; import org.briarproject.briar.android.socialbackup.recover.OwnerRecoveryModeExplainerFragment; +import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardActivity; import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardFragment; import org.briarproject.briar.android.socialbackup.recover.RecoverActivity; import org.briarproject.briar.android.socialbackup.ShardsSentFragment; @@ -205,7 +206,9 @@ public interface ActivityComponent { void inject(ReturnShardActivity returnShardActivity); - void inject(CustodianReturnShardActivity custodianSendShardActivity); + void inject(CustodianReturnShardActivity custodianReturnShardActivity); + + void inject(OwnerReturnShardActivity ownerReturnShardActivity); // Fragments diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java index c2982f698..08f6e4e61 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java @@ -12,15 +12,13 @@ import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BaseActivity; import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactErrorFragment; import org.briarproject.briar.android.fragment.BaseFragment; -import org.briarproject.briar.android.util.RequestBluetoothDiscoverable; +import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; import java.util.logging.Logger; import javax.annotation.Nullable; import javax.inject.Inject; -import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts; import androidx.fragment.app.FragmentManager; import androidx.lifecycle.ViewModelProvider; @@ -87,8 +85,8 @@ public class OwnerReturnShardActivity extends BaseActivity viewModel.getShowQrCodeFragment().observeEvent(this, show -> { if (show) showQrCodeFragment(); }); -// viewModel.getState() -// .observe(this, this::onReturnShardStateChanged); + viewModel.getState() + .observe(this, this::onReturnShardStateChanged); } @Override @@ -120,9 +118,9 @@ public class OwnerReturnShardActivity extends BaseActivity @Override public void onBackPressed() { if (viewModel.getState() - .getValue() instanceof ReturnShardState.Failed) { + .getValue() instanceof SecretOwnerTask.State.Failure) { // re-create this activity when going back in failed state - Intent i = new Intent(this, ReturnShardActivity.class); + Intent i = new Intent(this, OwnerReturnShardActivity.class); i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); startActivity(i); } else { @@ -141,16 +139,16 @@ public class OwnerReturnShardActivity extends BaseActivity } } - private void onReturnShardStateChanged(ReturnShardState state) { - if (state instanceof ReturnShardState.SocialBackupExchangeFinished) { - ReturnShardState.SocialBackupExchangeResult result = - ((ReturnShardState.SocialBackupExchangeFinished) state).result; - onSocialBackupExchangeResult(result); - } else if (state instanceof ReturnShardState.Failed) { - Boolean qrCodeTooOld = - ((ReturnShardState.Failed) state).qrCodeTooOld; - onAddingContactFailed(qrCodeTooOld); - } + private void onReturnShardStateChanged(SecretOwnerTask.State state) { +// if (state instanceof ReturnShardState.SocialBackupExchangeFinished) { +// ReturnShardState.SocialBackupExchangeResult result = +// ((ReturnShardState.SocialBackupExchangeFinished) state).result; +// onSocialBackupExchangeResult(result); +// } else if (state instanceof ReturnShardState.Failed) { +// Boolean qrCodeTooOld = +// ((ReturnShardState.Failed) state).qrCodeTooOld; +// onAddingContactFailed(qrCodeTooOld); +// } } private void onSocialBackupExchangeResult( diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java index 8582466d9..2c9f5e474 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java @@ -129,8 +129,7 @@ public class OwnerReturnShardFragment extends BaseFragment @UiThread private void onReturnShardStateChanged(@Nullable SecretOwnerTask.State state) { if (state instanceof SecretOwnerTask.State.Listening) { - Bitmap qrCode = - ((ReturnShardState.KeyAgreementListening) state).qrCode; + Bitmap qrCode = viewModel.getQrCodeBitmap(); qrCodeView.setQrCode(qrCode); } else if (state instanceof SecretOwnerTask.State.ReceivingShard) { statusView.setVisibility(VISIBLE); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java index a4bb76a43..4c7917a6d 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java @@ -4,23 +4,14 @@ import android.app.Application; import android.graphics.Bitmap; import android.util.DisplayMetrics; -import org.briarproject.bramble.api.crypto.SecretKey; -import org.briarproject.bramble.api.db.ContactExistsException; -import org.briarproject.bramble.api.db.DbException; -import org.briarproject.bramble.api.keyagreement.KeyAgreementResult; -import org.briarproject.bramble.api.keyagreement.Payload; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import org.briarproject.bramble.api.plugin.TransportId; -import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.system.AndroidExecutor; 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.ReturnShardPayload; import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; -import java.io.IOException; import java.nio.charset.Charset; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -33,12 +24,10 @@ import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import static java.util.logging.Level.INFO; -import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.util.LogUtils.logException; @NotNullByDefault -class OwnerReturnShardViewModel extends AndroidViewModel { +class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerTask.Observer { private static final Logger LOG = getLogger(OwnerReturnShardViewModel.class.getName()); @@ -46,10 +35,11 @@ class OwnerReturnShardViewModel extends AndroidViewModel { @SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19 private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); - private ReturnShardPayload returnShardPayload; +// private ReturnShardPayload returnShardPayload; private final AndroidExecutor androidExecutor; private final Executor ioExecutor; + private final SecretOwnerTask task; private final MutableLiveEvent showQrCodeFragment = new MutableLiveEvent<>(); @@ -58,14 +48,17 @@ class OwnerReturnShardViewModel extends AndroidViewModel { private boolean wasContinueClicked = false; private boolean isActivityResumed = false; + private Bitmap qrCodeBitmap; @Inject OwnerReturnShardViewModel(Application app, AndroidExecutor androidExecutor, + SecretOwnerTask task, @IoExecutor Executor ioExecutor) { super(app); this.androidExecutor = androidExecutor; this.ioExecutor = ioExecutor; + this.task = task; // IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED); } @@ -89,11 +82,11 @@ class OwnerReturnShardViewModel extends AndroidViewModel { // If we return to the intro fragment, we may need to enable wifi and // hasEnabledWifi = false; startListening(); - showQrCodeFragment.setEvent(true); } @UiThread private void startListening() { + task.start(this); // KeyAgreementTask oldTask = task; // KeyAgreementTask newTask = keyAgreementTaskProvider.get(); // task = newTask; @@ -105,6 +98,7 @@ class OwnerReturnShardViewModel extends AndroidViewModel { @UiThread private void stopListening() { + task.cancel(); // KeyAgreementTask oldTask = task; // ioExecutor.execute(() -> { // if (oldTask != null) oldTask.stopListening(); @@ -153,26 +147,6 @@ class OwnerReturnShardViewModel extends AndroidViewModel { // } // } - /** - * This sets the QR code by setting the state to KeyAgreementListening. - */ - private void onLocalPayloadReceived(Payload localPayload) { - if (gotLocalPayload) return; - DisplayMetrics dm = getApplication().getResources().getDisplayMetrics(); - ioExecutor.execute(() -> { - byte[] payloadBytes = payloadEncoder.encode(localPayload); - if (LOG.isLoggable(INFO)) { - LOG.info("Local payload is " + payloadBytes.length - + " bytes"); - } - // Use ISO 8859-1 to encode bytes directly as a string - String content = new String(payloadBytes, ISO_8859_1); - Bitmap qrCode = QrCodeUtils.createQrCode(dm, content); - gotLocalPayload = true; - state.postValue(new SecretOwnerTask.State.Listening(qrCode)); - }); - } - @UiThread // private void startContactExchange(KeyAgreementResult result) { // TransportId t = result.getTransportId(); @@ -218,7 +192,6 @@ class OwnerReturnShardViewModel extends AndroidViewModel { * https://issuetracker.google.com/issues/37067655. * TODO check if this is still happening with new permission requesting */ - @UiThread void setIsActivityResumed(boolean resumed) { isActivityResumed = resumed; // Workaround for @@ -233,4 +206,26 @@ class OwnerReturnShardViewModel extends AndroidViewModel { LiveData getState() { return state; } + + public Bitmap getQrCodeBitmap() { + return qrCodeBitmap; + } + + @Override + public void onStateChanged(SecretOwnerTask.State state) { + if (state instanceof SecretOwnerTask.State.Listening) { + DisplayMetrics dm = getApplication().getResources().getDisplayMetrics(); + ioExecutor.execute(() -> { + byte[] payloadBytes = ((SecretOwnerTask.State.Listening) state).getLocalPayload(); + if (LOG.isLoggable(INFO)) { + LOG.info("Local payload is " + payloadBytes.length + + " bytes"); + } + // Use ISO 8859-1 to encode bytes directly as a string + String content = new String(payloadBytes, ISO_8859_1); + qrCodeBitmap = QrCodeUtils.createQrCode(dm, content); + showQrCodeFragment.setEvent(true); + }); + } + } } From b55ae1ce1863e19c3c01240334bd52a6264044d1 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 12 Apr 2021 15:03:50 +0200 Subject: [PATCH 10/48] Changes to implementation for SecertOwnerTask --- .../briar/api/socialbackup/recovery/SecretOwnerTask.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java index 0278645d5..2a3f3a37a 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java @@ -22,11 +22,14 @@ public interface SecretOwnerTask { private final PublicKey publicKey; private final InetSocketAddress socketAddress; + private final byte[] localPayload; public Listening(PublicKey publicKey, InetSocketAddress socketAddress) { this.publicKey = publicKey; this.socketAddress = socketAddress; + // TODO this should also include the socket address + this.localPayload = publicKey.getEncoded(); } public PublicKey getPublicKey() { @@ -36,6 +39,10 @@ public interface SecretOwnerTask { public InetSocketAddress getSocketAddress() { return socketAddress; } + + public byte[] getLocalPayload() { + return localPayload; + } } public static class ReceivingShard extends State { From c0827eda773330e2372e0392238482adbf6eaf94 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 12 Apr 2021 15:57:15 +0200 Subject: [PATCH 11/48] use the new OwnerReturnShardActivity --- briar-android/src/main/AndroidManifest.xml | 2 +- .../briar/android/account/NewOrRecoverActivity.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml index d8353ebe9..3b43f6d8d 100644 --- a/briar-android/src/main/AndroidManifest.xml +++ b/briar-android/src/main/AndroidManifest.xml @@ -166,7 +166,7 @@ Date: Mon, 12 Apr 2021 16:15:52 +0200 Subject: [PATCH 12/48] rename ReturnShardModule, it is now only used by secret owner --- .../{ReturnShardModule.java => OwnerReturnShardModule.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/{ReturnShardModule.java => OwnerReturnShardModule.java} (100%) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/ReturnShardModule.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardModule.java similarity index 100% rename from briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/ReturnShardModule.java rename to briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardModule.java From 5fd0d0d2d313a4ed807923cfc5cfb60e30a68b01 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 12 Apr 2021 16:17:22 +0200 Subject: [PATCH 13/48] OwnerReturnShard activity and view model now running --- .../java/org/briarproject/briar/android/AppModule.java | 4 ++-- .../recover/OwnerRecoveryModeExplainerFragment.java | 4 ++-- .../socialbackup/recover/OwnerReturnShardFragment.java | 3 --- .../socialbackup/recover/OwnerReturnShardModule.java | 8 ++++---- .../socialbackup/recover/OwnerReturnShardViewModel.java | 2 +- 5 files changed, 9 insertions(+), 12 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java index b9a4c83d5..7d1cdff94 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java @@ -42,7 +42,7 @@ import org.briarproject.briar.android.privategroup.list.GroupListModule; import org.briarproject.briar.android.reporting.DevReportModule; import org.briarproject.briar.android.settings.SettingsModule; import org.briarproject.briar.android.sharing.SharingModule; -import org.briarproject.briar.android.socialbackup.recover.ReturnShardModule; +import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardModule; import org.briarproject.briar.android.test.TestAvatarCreatorImpl; import org.briarproject.briar.android.viewmodel.ViewModelModule; import org.briarproject.briar.api.android.AndroidNotificationManager; @@ -92,7 +92,7 @@ import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD; GroupListModule.class, GroupConversationModule.class, SharingModule.class, - ReturnShardModule.class + OwnerReturnShardModule.class }) public class AppModule { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerRecoveryModeExplainerFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerRecoveryModeExplainerFragment.java index 370cb71c8..cf047012e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerRecoveryModeExplainerFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerRecoveryModeExplainerFragment.java @@ -24,7 +24,7 @@ public class OwnerRecoveryModeExplainerFragment extends BaseFragment { @Inject ViewModelProvider.Factory viewModelFactory; - private ReturnShardViewModel viewModel; + private OwnerReturnShardViewModel viewModel; // @Override // public void onCreate(@Nullable Bundle savedInstanceState) { @@ -36,7 +36,7 @@ public class OwnerRecoveryModeExplainerFragment extends BaseFragment { public void injectFragment(ActivityComponent component) { component.inject(this); viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) - .get(ReturnShardViewModel.class); + .get(OwnerReturnShardViewModel.class); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java index 2c9f5e474..978eb949b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java @@ -33,9 +33,6 @@ import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.widget.LinearLayout.HORIZONTAL; -import static android.widget.Toast.LENGTH_LONG; -import static java.util.logging.Level.WARNING; -import static org.briarproject.bramble.util.LogUtils.logException; @MethodsNotNullByDefault @ParametersNotNullByDefault diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardModule.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardModule.java index 749e37a90..b2f2da6e4 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardModule.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardModule.java @@ -9,12 +9,12 @@ import dagger.multibindings.IntoMap; @Module -public abstract class ReturnShardModule { +public abstract class OwnerReturnShardModule { @Binds @IntoMap - @ViewModelKey(ReturnShardViewModel.class) - abstract ViewModel bindContactExchangeViewModel( - ReturnShardViewModel returnShardViewModel); + @ViewModelKey(OwnerReturnShardViewModel.class) + abstract ViewModel bindOwnerReturnShardViewModel( + OwnerReturnShardViewModel ownerReturnShardViewModel); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java index 4c7917a6d..c77ec478c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java @@ -224,8 +224,8 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT // Use ISO 8859-1 to encode bytes directly as a string String content = new String(payloadBytes, ISO_8859_1); qrCodeBitmap = QrCodeUtils.createQrCode(dm, content); - showQrCodeFragment.setEvent(true); }); + showQrCodeFragment.setEvent(true); } } } From e106166cfe0f3f3f8ea272129afe0bfecde1c58c Mon Sep 17 00:00:00 2001 From: ameba23 Date: Mon, 12 Apr 2021 16:18:23 +0200 Subject: [PATCH 14/48] provide SecretOwnerTask --- .../briar/socialbackup/SocialBackupModule.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupModule.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupModule.java index b624024cb..7c3c5490d 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupModule.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupModule.java @@ -10,6 +10,8 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.conversation.ConversationManager; import org.briarproject.briar.api.socialbackup.SocialBackupExchangeManager; import org.briarproject.briar.api.socialbackup.SocialBackupManager; +import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; +import org.briarproject.briar.socialbackup.recovery.SecretOwnerTaskImpl; import javax.inject.Inject; import javax.inject.Singleton; @@ -96,4 +98,9 @@ public class SocialBackupModule { SocialBackupExchangeManager socialBackupExchangeManager(SocialBackupExchangeManagerImpl socialBackupExchangeManager) { return socialBackupExchangeManager; } + + @Provides + SecretOwnerTask secretOwnerTask(SecretOwnerTaskImpl secretOwnerTask) { + return secretOwnerTask; + } } From 01bcc6d4911d7cef270f13e31e68a3038262ea1f Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 13 Apr 2021 08:52:42 +0200 Subject: [PATCH 15/48] ensure that qr code is ready when start button is pressed --- .../recover/OwnerReturnShardActivity.java | 1 + .../recover/OwnerReturnShardFragment.java | 26 ++++++++++++------- .../recover/OwnerReturnShardViewModel.java | 5 ++-- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java index 08f6e4e61..91770a459 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java @@ -129,6 +129,7 @@ public class OwnerReturnShardActivity extends BaseActivity } private void showQrCodeFragment() { + LOG.info("showQrCodeFragment called"); FragmentManager fm = getSupportFragmentManager(); if (fm.findFragmentByTag(OwnerReturnShardFragment.TAG) == null) { BaseFragment f = OwnerReturnShardFragment.newInstance(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java index 978eb949b..686f14cf7 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardFragment.java @@ -7,14 +7,11 @@ import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; -import android.widget.Toast; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; -import org.briarproject.briar.android.contact.add.nearby.CameraException; -import org.briarproject.briar.android.contact.add.nearby.CameraView; import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.view.QrCodeView; import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; @@ -86,6 +83,10 @@ public class OwnerReturnShardFragment extends BaseFragment viewModel.getState().observe(getViewLifecycleOwner(), this::onReturnShardStateChanged); + Bitmap qrCodeBitmap = viewModel.getQrCodeBitmap(); + if (qrCodeBitmap != null) { + qrCodeView.setQrCode(qrCodeBitmap); + } } @Override @@ -107,15 +108,21 @@ public class OwnerReturnShardFragment extends BaseFragment if (fullscreen) { // Grow the QR code view to fill its parent statusParams = new LinearLayout.LayoutParams(0, 0, 0f); - qrCodeParams = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT, 1f); + qrCodeParams = + new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT, + 1f); } else { // Shrink the QR code view to fill half its parent if (cameraOverlay.getOrientation() == HORIZONTAL) { - statusParams = new LinearLayout.LayoutParams(0, MATCH_PARENT, 1f); - qrCodeParams = new LinearLayout.LayoutParams(0, MATCH_PARENT, 1f); + statusParams = + new LinearLayout.LayoutParams(0, MATCH_PARENT, 1f); + qrCodeParams = + new LinearLayout.LayoutParams(0, MATCH_PARENT, 1f); } else { - statusParams = new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1f); - qrCodeParams = new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1f); + statusParams = + new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1f); + qrCodeParams = + new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1f); } } statusView.setLayoutParams(statusParams); @@ -124,7 +131,8 @@ public class OwnerReturnShardFragment extends BaseFragment } @UiThread - private void onReturnShardStateChanged(@Nullable SecretOwnerTask.State state) { + private void onReturnShardStateChanged( + @Nullable SecretOwnerTask.State state) { if (state instanceof SecretOwnerTask.State.Listening) { Bitmap qrCode = viewModel.getQrCodeBitmap(); qrCodeView.setQrCode(qrCode); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java index c77ec478c..9997f35c6 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java @@ -60,6 +60,7 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT this.ioExecutor = ioExecutor; this.task = task; // IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED); + startListening(); } @Override @@ -81,7 +82,7 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT wasContinueClicked = false; // If we return to the intro fragment, we may need to enable wifi and // hasEnabledWifi = false; - startListening(); + showQrCodeFragment.setEvent(true); } @UiThread @@ -208,6 +209,7 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT } public Bitmap getQrCodeBitmap() { + LOG.info("getting qrCodeBitmap"); return qrCodeBitmap; } @@ -225,7 +227,6 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT String content = new String(payloadBytes, ISO_8859_1); qrCodeBitmap = QrCodeUtils.createQrCode(dm, content); }); - showQrCodeFragment.setEvent(true); } } } From dba4cc278c50fc84b27aebc99ca5ccd9b778f6cf Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 13 Apr 2021 08:53:27 +0200 Subject: [PATCH 16/48] dummy ip address for local socket --- .../briar/socialbackup/recovery/SecretOwnerTaskImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java index 0a7439b59..82508aa87 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java @@ -28,7 +28,7 @@ public class SecretOwnerTaskImpl implements SecretOwnerTask { @Override public void start(Observer observer) { // TODO use the actual ip address on local network - InetSocketAddress socketAddress = InetSocketAddress.createUnresolved("localhost", 1234); + InetSocketAddress socketAddress = InetSocketAddress.createUnresolved("192.168.1.1", 1234); observer.onStateChanged(new State.Listening(localKeyPair.getPublic(), socketAddress)); } From d6608fd8cbd2fc3b2bd6424328bc212480405188 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 13 Apr 2021 09:19:42 +0200 Subject: [PATCH 17/48] add a CustodianReturnShardModule which provides the view model --- briar-android/src/main/AndroidManifest.xml | 9 +++++++++ .../briarproject/briar/android/AppModule.java | 4 +++- .../recover/CustodianReturnShardActivity.java | 5 +++-- .../recover/CustodianReturnShardModule.java | 19 +++++++++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardModule.java diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml index 3b43f6d8d..de07b1173 100644 --- a/briar-android/src/main/AndroidManifest.xml +++ b/briar-android/src/main/AndroidManifest.xml @@ -165,6 +165,15 @@ android:value="org.briarproject.briar.android.account.NewOrRecoverActivity" /> + + + + Date: Tue, 13 Apr 2021 09:20:37 +0200 Subject: [PATCH 18/48] Temporary - allow us to jump to the custodian return shard activity directly from the settings menu, even if we dont hold any shards --- briar-android/src/main/res/xml/settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/briar-android/src/main/res/xml/settings.xml b/briar-android/src/main/res/xml/settings.xml index dfa35a0dd..d7ae38e4a 100644 --- a/briar-android/src/main/res/xml/settings.xml +++ b/briar-android/src/main/res/xml/settings.xml @@ -96,7 +96,7 @@ app:iconSpaceReserved="false"> From df37a39cb4c581759c44a748f163a2b227468e2e Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 13 Apr 2021 11:13:28 +0200 Subject: [PATCH 19/48] Qr code payload contains socket address and public key --- .../recover/CustodianReturnShardActivity.java | 13 ++++---- .../CustodianReturnShardViewModel.java | 24 +++++++++----- .../socialbackup/recovery/CustodianTask.java | 2 ++ .../recovery/SecretOwnerTask.java | 18 ++--------- .../socialbackup/SocialBackupModule.java | 7 ++++ .../recovery/CustodianTaskImpl.java | 32 ++++++++++++++++++- .../recovery/SecretOwnerTaskImpl.java | 24 ++++++++++++-- 7 files changed, 86 insertions(+), 34 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java index b5ca3e5e9..092ee8981 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java @@ -7,6 +7,7 @@ import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BriarActivity; import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.socialbackup.CustodianRecoveryModeExplainerFragment; +import org.briarproject.briar.api.socialbackup.recovery.CustodianTask; import java.util.logging.Logger; @@ -55,15 +56,15 @@ public class CustodianReturnShardActivity extends BriarActivity if (state == null) { showInitialFragment(new CustodianRecoveryModeExplainerFragment()); } -// viewModel.getCheckPermissions().observeEvent(this, check -> -// permissionManager.checkPermissions()); -// viewModel.getRequestBluetoothDiscoverable().observeEvent(this, r -> -// requestBluetoothDiscoverable()); // never false viewModel.getShowCameraFragment().observeEvent(this, show -> { if (show) showCameraFragment(); }); -// viewModel.getState() -// .observe(this, this::onReturnShardStateChanged); + viewModel.getState() + .observe(this, this::onReturnShardStateChanged); + } + + private void onReturnShardStateChanged(CustodianTask.State state) { + } private void showCameraFragment() { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java index b454ca859..c4a94cf3e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java @@ -14,6 +14,7 @@ import org.briarproject.briar.android.contact.add.nearby.QrCodeDecoder; import org.briarproject.briar.android.viewmodel.LiveEvent; import org.briarproject.briar.android.viewmodel.MutableLiveEvent; import org.briarproject.briar.api.socialbackup.recovery.CustodianTask; +import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; import java.io.IOException; import java.nio.charset.Charset; @@ -36,7 +37,7 @@ import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; public class CustodianReturnShardViewModel extends AndroidViewModel - implements QrCodeDecoder.ResultCallback { + implements QrCodeDecoder.ResultCallback, CustodianTask.Observer { private static final Logger LOG = getLogger(CustodianReturnShardViewModel.class.getName()); @@ -49,6 +50,7 @@ public class CustodianReturnShardViewModel extends AndroidViewModel private final MutableLiveData state = new MutableLiveData<>(); final QrCodeDecoder qrCodeDecoder; + private final CustodianTask task; @SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19 private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); @@ -57,12 +59,15 @@ public class CustodianReturnShardViewModel extends AndroidViewModel public CustodianReturnShardViewModel( @NonNull Application application, @IoExecutor Executor ioExecutor, + CustodianTask task, AndroidExecutor androidExecutor) { super(application); this.androidExecutor = androidExecutor; this.ioExecutor = ioExecutor; + this.task = task; qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this); + task.start(this); } @IoExecutor @@ -75,17 +80,12 @@ public class CustodianReturnShardViewModel extends AndroidViewModel byte[] payloadBytes = result.getText().getBytes(ISO_8859_1); if (LOG.isLoggable(INFO)) LOG.info("Remote payload is " + payloadBytes.length + " bytes"); -// Payload remotePayload = payloadParser.parse(payloadBytes); -// gotRemotePayload = true; -// requireNonNull(task).connectAndRunProtocol(remotePayload); -// state.postValue(new ReturnShardState.QrCodeScanned()); + task.qrCodeDecoded(payloadBytes); } catch (IllegalArgumentException e) { LOG.log(WARNING, "QR Code Invalid", e); androidExecutor.runOnUiThread(() -> Toast.makeText(getApplication(), R.string.qr_code_invalid, LENGTH_LONG).show()); -// resetPayloadFlags(); - state.postValue(new CustodianTask.State.Failure( - CustodianTask.State.Failure.Reason.QR_CODE_INVALID)); + task.qrCodeDecoded(null); } } @@ -107,4 +107,12 @@ public class CustodianReturnShardViewModel extends AndroidViewModel LiveData getState() { return state; } + + @Override + public void onStateChanged(CustodianTask.State state) { + // Connecting, SendingShard, ReceivingAck, Success, Failure + if (state instanceof CustodianTask.State.SendingShard) { + + } + } } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/CustodianTask.java b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/CustodianTask.java index 91bc9060b..9b93ea4b4 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/CustodianTask.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/CustodianTask.java @@ -9,6 +9,8 @@ public interface CustodianTask { void cancel(); + void qrCodeDecoded(byte[] qrCodePayload); + interface Observer { void onStateChanged(State state); } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java index 2a3f3a37a..5fd3c3205 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java @@ -20,24 +20,10 @@ public interface SecretOwnerTask { public static class Listening extends State { - private final PublicKey publicKey; - private final InetSocketAddress socketAddress; private final byte[] localPayload; - public Listening(PublicKey publicKey, - InetSocketAddress socketAddress) { - this.publicKey = publicKey; - this.socketAddress = socketAddress; - // TODO this should also include the socket address - this.localPayload = publicKey.getEncoded(); - } - - public PublicKey getPublicKey() { - return publicKey; - } - - public InetSocketAddress getSocketAddress() { - return socketAddress; + public Listening(byte[] localPayload) { + this.localPayload = localPayload; } public byte[] getLocalPayload() { diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupModule.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupModule.java index 7c3c5490d..d66338dbb 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupModule.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupModule.java @@ -10,7 +10,9 @@ import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.briar.api.conversation.ConversationManager; import org.briarproject.briar.api.socialbackup.SocialBackupExchangeManager; import org.briarproject.briar.api.socialbackup.SocialBackupManager; +import org.briarproject.briar.api.socialbackup.recovery.CustodianTask; import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; +import org.briarproject.briar.socialbackup.recovery.CustodianTaskImpl; import org.briarproject.briar.socialbackup.recovery.SecretOwnerTaskImpl; import javax.inject.Inject; @@ -103,4 +105,9 @@ public class SocialBackupModule { SecretOwnerTask secretOwnerTask(SecretOwnerTaskImpl secretOwnerTask) { return secretOwnerTask; } + + @Provides + CustodianTask custodianTask(CustodianTaskImpl custodianTask) { + return custodianTask; + } } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java index af89bde8b..8106cef20 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java @@ -1,15 +1,45 @@ package org.briarproject.briar.socialbackup.recovery; +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.data.BdfList; import org.briarproject.briar.api.socialbackup.recovery.CustodianTask; +import javax.inject.Inject; + public class CustodianTaskImpl implements CustodianTask { + + private boolean cancelled = false; + private Observer observer; + private ClientHelper clientHelper; + + @Inject + CustodianTaskImpl(ClientHelper clientHelper) { + this.clientHelper = clientHelper; + } + @Override public void start(Observer observer) { - + this.observer = observer; + observer.onStateChanged(new CustodianTask.State.Connecting()); } @Override public void cancel() { + cancelled = true; + } + @Override + public void qrCodeDecoded(byte[] qrCodePayloadRaw) { + try { + BdfList qrCodePayload = clientHelper.toList(qrCodePayloadRaw); + byte[] publicKeyRaw = qrCodePayload.getRaw(0); + byte[] addressRaw = qrCodePayload.getRaw(1); + Long port = qrCodePayload.getLong(2); + System.out.println(" Qr code decoded " + publicKeyRaw.length + " " + addressRaw.length + " "+ port); + observer.onStateChanged(new CustodianTask.State.SendingShard()); + } catch (FormatException e) { + observer.onStateChanged(new CustodianTask.State.Failure(State.Failure.Reason.QR_CODE_INVALID)); + } } } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java index 82508aa87..915986868 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java @@ -1,10 +1,14 @@ package org.briarproject.briar.socialbackup.recovery; +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.KeyPair; +import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.concurrent.Executor; @@ -16,20 +20,34 @@ public class SecretOwnerTaskImpl implements SecretOwnerTask { private final Executor ioExecutor; private final KeyPair localKeyPair; private boolean cancelled = false; + private InetSocketAddress socketAddress; + private ClientHelper clientHelper; @Inject SecretOwnerTaskImpl(CryptoComponent crypto, - @IoExecutor Executor ioExecutor) { + @IoExecutor Executor ioExecutor, ClientHelper clientHelper) { this.crypto = crypto; this.ioExecutor = ioExecutor; + this.clientHelper = clientHelper; localKeyPair = crypto.generateAgreementKeyPair(); } @Override public void start(Observer observer) { // TODO use the actual ip address on local network - InetSocketAddress socketAddress = InetSocketAddress.createUnresolved("192.168.1.1", 1234); - observer.onStateChanged(new State.Listening(localKeyPair.getPublic(), socketAddress)); + byte[] hostBytes = { (byte) 192, (byte) 168, 1,1}; + // TODO add version number + try { + BdfList payloadList = new BdfList(); + socketAddress = new InetSocketAddress(InetAddress.getByAddress(hostBytes), 1234); + payloadList.add(localKeyPair.getPublic().getEncoded()); + payloadList.add(socketAddress.getAddress().getAddress()); + payloadList.add(socketAddress.getPort()); + observer.onStateChanged( + new State.Listening(clientHelper.toByteArray(payloadList))); + } catch (Exception e) { + observer.onStateChanged(new State.Failure()); + } } @Override From cd1ac43b7d70b897faaaada592ef9f513c3272d8 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 13 Apr 2021 11:56:52 +0200 Subject: [PATCH 20/48] get the actual ip address on local wifi and add it to qr code --- .../recover/OwnerReturnShardViewModel.java | 39 ++++++++++++++++++- .../recovery/SecretOwnerTask.java | 3 +- .../recovery/CustodianTaskImpl.java | 15 +++++-- .../recovery/SecretOwnerTaskImpl.java | 11 +++--- 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java index 9997f35c6..31f1dbe42 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java @@ -2,8 +2,11 @@ package org.briarproject.briar.android.socialbackup.recover; import android.app.Application; import android.graphics.Bitmap; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; import android.util.DisplayMetrics; +import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.system.AndroidExecutor; @@ -12,17 +15,23 @@ import org.briarproject.briar.android.viewmodel.LiveEvent; import org.briarproject.briar.android.viewmodel.MutableLiveEvent; import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.UnknownHostException; import java.nio.charset.Charset; +import java.util.List; import java.util.concurrent.Executor; import java.util.logging.Logger; import javax.inject.Inject; +import androidx.annotation.Nullable; import androidx.annotation.UiThread; import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; +import static android.content.Context.WIFI_SERVICE; import static java.util.logging.Level.INFO; import static java.util.logging.Logger.getLogger; @@ -45,10 +54,10 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT new MutableLiveEvent<>(); private final MutableLiveData state = new MutableLiveData<>(); - private boolean wasContinueClicked = false; private boolean isActivityResumed = false; private Bitmap qrCodeBitmap; + private WifiManager wifiManager; @Inject OwnerReturnShardViewModel(Application app, @@ -59,10 +68,36 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT this.androidExecutor = androidExecutor; this.ioExecutor = ioExecutor; this.task = task; + wifiManager = (WifiManager) app.getSystemService(WIFI_SERVICE); + // IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED); startListening(); } + private InetAddress getWifiIpv4Address() { + if (wifiManager == null) return null; + // If we're connected to a wifi network, return its address + WifiInfo info = wifiManager.getConnectionInfo(); + if (info != null && info.getIpAddress() != 0) { + return intToInetAddress(info.getIpAddress()); + } + return null; + } + + private InetAddress intToInetAddress(int ip) { + byte[] ipBytes = new byte[4]; + ipBytes[0] = (byte) (ip & 0xFF); + ipBytes[1] = (byte) ((ip >> 8) & 0xFF); + ipBytes[2] = (byte) ((ip >> 16) & 0xFF); + ipBytes[3] = (byte) ((ip >> 24) & 0xFF); + try { + return InetAddress.getByAddress(ipBytes); + } catch (UnknownHostException e) { + // Should only be thrown if address has illegal length + throw new AssertionError(e); + } + } + @Override protected void onCleared() { super.onCleared(); @@ -87,7 +122,7 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT @UiThread private void startListening() { - task.start(this); + task.start(this, getWifiIpv4Address()); // KeyAgreementTask oldTask = task; // KeyAgreementTask newTask = keyAgreementTaskProvider.get(); // task = newTask; diff --git a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java index 5fd3c3205..7e5b3f73c 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/SecretOwnerTask.java @@ -3,12 +3,13 @@ package org.briarproject.briar.api.socialbackup.recovery; import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import java.net.InetAddress; import java.net.InetSocketAddress; @NotNullByDefault public interface SecretOwnerTask { - void start(Observer observer); + void start(Observer observer, InetAddress inetAddress); void cancel(); diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java index 8106cef20..a57ce86df 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java @@ -2,9 +2,14 @@ package org.briarproject.briar.socialbackup.recovery; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.crypto.AgreementPublicKey; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.briar.api.socialbackup.recovery.CustodianTask; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.security.PublicKey; + import javax.inject.Inject; public class CustodianTaskImpl implements CustodianTask { @@ -12,6 +17,7 @@ public class CustodianTaskImpl implements CustodianTask { private boolean cancelled = false; private Observer observer; private ClientHelper clientHelper; + private InetSocketAddress remoteSocketAddress; @Inject CustodianTaskImpl(ClientHelper clientHelper) { @@ -33,12 +39,13 @@ public class CustodianTaskImpl implements CustodianTask { public void qrCodeDecoded(byte[] qrCodePayloadRaw) { try { BdfList qrCodePayload = clientHelper.toList(qrCodePayloadRaw); - byte[] publicKeyRaw = qrCodePayload.getRaw(0); + AgreementPublicKey publicKey = new AgreementPublicKey(qrCodePayload.getRaw(0)); byte[] addressRaw = qrCodePayload.getRaw(1); - Long port = qrCodePayload.getLong(2); - System.out.println(" Qr code decoded " + publicKeyRaw.length + " " + addressRaw.length + " "+ port); + int port = qrCodePayload.getLong(2).intValue(); + remoteSocketAddress = new InetSocketAddress(InetAddress.getByAddress(addressRaw), port); + System.out.println(" Qr code decoded " + publicKey.getEncoded().length + " " + remoteSocketAddress); observer.onStateChanged(new CustodianTask.State.SendingShard()); - } catch (FormatException e) { + } catch (Exception e) { observer.onStateChanged(new CustodianTask.State.Failure(State.Failure.Reason.QR_CODE_INVALID)); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java index 915986868..c35c7eb12 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java @@ -33,13 +33,14 @@ public class SecretOwnerTaskImpl implements SecretOwnerTask { } @Override - public void start(Observer observer) { - // TODO use the actual ip address on local network - byte[] hostBytes = { (byte) 192, (byte) 168, 1,1}; - // TODO add version number + public void start(Observer observer, InetAddress inetAddress) { + if (inetAddress == null) observer.onStateChanged(new State.Failure()); + System.out.println("InetAddress is " + inetAddress); + socketAddress = new InetSocketAddress(inetAddress, 3002); + // TODO start listening on socketAddress try { + // TODO add version number BdfList payloadList = new BdfList(); - socketAddress = new InetSocketAddress(InetAddress.getByAddress(hostBytes), 1234); payloadList.add(localKeyPair.getPublic().getEncoded()); payloadList.add(socketAddress.getAddress().getAddress()); payloadList.add(socketAddress.getPort()); From 1bf9f57ad9ba9b309d4b341792760e8c8ff4716b Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 13 Apr 2021 12:20:17 +0200 Subject: [PATCH 21/48] secret owner listens, and custodian connects --- .../socialbackup/recovery/CustodianTaskImpl.java | 11 +++++++++++ .../recovery/SecretOwnerTaskImpl.java | 15 ++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java index a57ce86df..def30433e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java @@ -6,8 +6,10 @@ import org.briarproject.bramble.api.crypto.AgreementPublicKey; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.briar.api.socialbackup.recovery.CustodianTask; +import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.Socket; import java.security.PublicKey; import javax.inject.Inject; @@ -47,6 +49,15 @@ public class CustodianTaskImpl implements CustodianTask { observer.onStateChanged(new CustodianTask.State.SendingShard()); } catch (Exception e) { observer.onStateChanged(new CustodianTask.State.Failure(State.Failure.Reason.QR_CODE_INVALID)); + return; } + + Socket s = new Socket(); + try { + s.connect(remoteSocketAddress); + } catch (IOException e) { + observer.onStateChanged(new CustodianTask.State.Failure(State.Failure.Reason.QR_CODE_INVALID)); + } + System.out.println("Connected *****"); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java index c35c7eb12..4da5659d8 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java @@ -8,8 +8,10 @@ import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; +import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.ServerSocket; import java.util.concurrent.Executor; import javax.inject.Inject; @@ -37,7 +39,18 @@ public class SecretOwnerTaskImpl implements SecretOwnerTask { if (inetAddress == null) observer.onStateChanged(new State.Failure()); System.out.println("InetAddress is " + inetAddress); socketAddress = new InetSocketAddress(inetAddress, 3002); - // TODO start listening on socketAddress + + // start listening on socketAddress + ServerSocket ss = null; + try { + ss = new ServerSocket(); + ss.bind(socketAddress); + } catch (IOException e) { + observer.onStateChanged(new State.Failure()); + // TODO could try incrementing the port number + return; + } + try { // TODO add version number BdfList payloadList = new BdfList(); From 4da20a24129080a5ecacabe3ebd97e89e8082ef8 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 13 Apr 2021 12:29:33 +0200 Subject: [PATCH 22/48] add timeout to client --- .../briar/socialbackup/recovery/CustodianTaskImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java index def30433e..70a8f106a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java @@ -54,7 +54,7 @@ public class CustodianTaskImpl implements CustodianTask { Socket s = new Socket(); try { - s.connect(remoteSocketAddress); + s.connect(remoteSocketAddress, 120 * 1000); } catch (IOException e) { observer.onStateChanged(new CustodianTask.State.Failure(State.Failure.Reason.QR_CODE_INVALID)); } From 6a143eea8a7b5aa6a745c2367df1ba830e6e4faa Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 13 Apr 2021 17:37:29 +0200 Subject: [PATCH 23/48] Update state in UI for Custodian --- .../recover/CustodianReturnShardActivity.java | 2 ++ .../recover/CustodianReturnShardFragment.java | 14 +++++++++++--- .../recover/CustodianReturnShardViewModel.java | 15 ++++++++++----- .../recover/OwnerReturnShardViewModel.java | 4 +++- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java index 092ee8981..f808a37c3 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java @@ -64,7 +64,9 @@ public class CustodianReturnShardActivity extends BriarActivity } private void onReturnShardStateChanged(CustodianTask.State state) { + if (state instanceof CustodianTask.State.Success) { + } } private void showCameraFragment() { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardFragment.java index 220eeba31..d893b5b0b 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardFragment.java @@ -141,7 +141,17 @@ public class CustodianReturnShardFragment extends BaseFragment @UiThread private void onReturnShardStateChanged(@Nullable CustodianTask.State state) { - if (state instanceof CustodianTask.State.Connecting) { + LOG.info("State changed"); +// if (state instanceof CustodianTask.State.Connecting) { +// try { +// cameraView.stop(); +// } catch (CameraException e) { +// logCameraExceptionAndFinish(e); +// } +// cameraView.setVisibility(INVISIBLE); +// statusView.setVisibility(VISIBLE); +// status.setText(R.string.connecting_to_device); + if (state instanceof CustodianTask.State.SendingShard) { try { cameraView.stop(); } catch (CameraException e) { @@ -149,8 +159,6 @@ public class CustodianReturnShardFragment extends BaseFragment } cameraView.setVisibility(INVISIBLE); statusView.setVisibility(VISIBLE); - status.setText(R.string.connecting_to_device); - } else if (state instanceof CustodianTask.State.SendingShard) { status.setText("Sending shard"); } else if (state instanceof CustodianTask.State.ReceivingAck) { status.setText("Receiving Ack"); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java index c4a94cf3e..6cb5a01e3 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java @@ -45,6 +45,7 @@ public class CustodianReturnShardViewModel extends AndroidViewModel private final AndroidExecutor androidExecutor; private final Executor ioExecutor; private boolean wasContinueClicked = false; + private boolean qrCodeRead = false; private final MutableLiveEvent showCameraFragment = new MutableLiveEvent<>(); private final MutableLiveData state = @@ -74,18 +75,21 @@ public class CustodianReturnShardViewModel extends AndroidViewModel @Override public void onQrCodeDecoded(Result result) { LOG.info("Got result from decoder"); - // Ignore results until the KeyAgreementTask is ready -// if (!gotLocalPayload || gotRemotePayload) return; + if (qrCodeRead) return; try { byte[] payloadBytes = result.getText().getBytes(ISO_8859_1); if (LOG.isLoggable(INFO)) LOG.info("Remote payload is " + payloadBytes.length + " bytes"); - task.qrCodeDecoded(payloadBytes); + ioExecutor.execute(() -> { + task.qrCodeDecoded(payloadBytes); + }); } catch (IllegalArgumentException e) { LOG.log(WARNING, "QR Code Invalid", e); androidExecutor.runOnUiThread(() -> Toast.makeText(getApplication(), R.string.qr_code_invalid, LENGTH_LONG).show()); - task.qrCodeDecoded(null); + ioExecutor.execute(() -> { + task.qrCodeDecoded(null); + }); } } @@ -110,9 +114,10 @@ public class CustodianReturnShardViewModel extends AndroidViewModel @Override public void onStateChanged(CustodianTask.State state) { + this.state.postValue(state); // Connecting, SendingShard, ReceivingAck, Success, Failure if (state instanceof CustodianTask.State.SendingShard) { - + qrCodeRead = true; } } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java index 31f1dbe42..6d9b4f130 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java @@ -122,7 +122,9 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT @UiThread private void startListening() { - task.start(this, getWifiIpv4Address()); + ioExecutor.execute(() -> { + task.start(this, getWifiIpv4Address()); + }); // KeyAgreementTask oldTask = task; // KeyAgreementTask newTask = keyAgreementTaskProvider.get(); // task = newTask; From d2abd6dcc2d9c175ec8dffbef1087736b4bef53d Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 13 Apr 2021 17:38:03 +0200 Subject: [PATCH 24/48] Basic handshake implementation --- .../recovery/CustodianTaskImpl.java | 84 ++++++++++++++----- .../recovery/SecretOwnerTaskImpl.java | 40 ++++++++- 2 files changed, 98 insertions(+), 26 deletions(-) diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java index 70a8f106a..348b914f9 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/CustodianTaskImpl.java @@ -1,16 +1,16 @@ package org.briarproject.briar.socialbackup.recovery; -import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.crypto.AgreementPublicKey; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.briar.api.socialbackup.recovery.CustodianTask; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; -import java.security.PublicKey; import javax.inject.Inject; @@ -20,6 +20,8 @@ public class CustodianTaskImpl implements CustodianTask { private Observer observer; private ClientHelper clientHelper; private InetSocketAddress remoteSocketAddress; + private Socket socket = new Socket(); + private final int TIMEOUT = 120 * 1000; @Inject CustodianTaskImpl(ClientHelper clientHelper) { @@ -34,30 +36,68 @@ public class CustodianTaskImpl implements CustodianTask { @Override public void cancel() { - cancelled = true; + cancelled = true; + try { + socket.close(); + } catch (IOException e) { + observer.onStateChanged(new CustodianTask.State.Failure( + State.Failure.Reason.NO_CONNECTION)); + } + observer.onStateChanged( + new CustodianTask.State.Failure(State.Failure.Reason.OTHER)); } @Override public void qrCodeDecoded(byte[] qrCodePayloadRaw) { - try { - BdfList qrCodePayload = clientHelper.toList(qrCodePayloadRaw); - AgreementPublicKey publicKey = new AgreementPublicKey(qrCodePayload.getRaw(0)); - byte[] addressRaw = qrCodePayload.getRaw(1); - int port = qrCodePayload.getLong(2).intValue(); - remoteSocketAddress = new InetSocketAddress(InetAddress.getByAddress(addressRaw), port); - System.out.println(" Qr code decoded " + publicKey.getEncoded().length + " " + remoteSocketAddress); - observer.onStateChanged(new CustodianTask.State.SendingShard()); - } catch (Exception e) { - observer.onStateChanged(new CustodianTask.State.Failure(State.Failure.Reason.QR_CODE_INVALID)); - return; - } + try { + BdfList qrCodePayload = clientHelper.toList(qrCodePayloadRaw); + AgreementPublicKey publicKey = + new AgreementPublicKey(qrCodePayload.getRaw(0)); + byte[] addressRaw = qrCodePayload.getRaw(1); + int port = qrCodePayload.getLong(2).intValue(); + remoteSocketAddress = + new InetSocketAddress(InetAddress.getByAddress(addressRaw), + port); + System.out.println( + " Qr code decoded " + publicKey.getEncoded().length + " " + + remoteSocketAddress); + } catch (Exception e) { + observer.onStateChanged(new CustodianTask.State.Failure( + State.Failure.Reason.QR_CODE_INVALID)); + return; + } + connectAndSendShard(); + } - Socket s = new Socket(); - try { - s.connect(remoteSocketAddress, 120 * 1000); - } catch (IOException e) { - observer.onStateChanged(new CustodianTask.State.Failure(State.Failure.Reason.QR_CODE_INVALID)); - } - System.out.println("Connected *****"); + private void connectAndSendShard() { + observer.onStateChanged(new CustodianTask.State.SendingShard()); + try { + socket.connect(remoteSocketAddress, TIMEOUT); + OutputStream outputStream = socket.getOutputStream(); + outputStream.write("crunchy".getBytes()); + observer.onStateChanged(new CustodianTask.State.ReceivingAck()); + } catch (IOException e) { + observer.onStateChanged(new CustodianTask.State.Failure( + State.Failure.Reason.QR_CODE_INVALID)); + return; + } + System.out.println("Connected *****"); + receiveAck(); + } + + private void receiveAck() { + try { + InputStream inputStream = socket.getInputStream(); + byte[] ackMessage = new byte[3]; + int read = inputStream.read(ackMessage); + if (read < 0) throw new IOException("Ack not read"); + System.out.println("ack message: " + new String(ackMessage)); + observer.onStateChanged(new CustodianTask.State.Success()); + socket.close(); + } catch (IOException e) { + observer.onStateChanged(new CustodianTask.State.Failure( + State.Failure.Reason.QR_CODE_INVALID)); + return; + } } } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java index 4da5659d8..e9f007d4c 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/SecretOwnerTaskImpl.java @@ -9,9 +9,12 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; +import java.net.Socket; import java.util.concurrent.Executor; import javax.inject.Inject; @@ -24,6 +27,10 @@ public class SecretOwnerTaskImpl implements SecretOwnerTask { private boolean cancelled = false; private InetSocketAddress socketAddress; private ClientHelper clientHelper; + private final int PORT = 3002; + private Observer observer; + private ServerSocket serverSocket; + private Socket socket; @Inject SecretOwnerTaskImpl(CryptoComponent crypto, @@ -36,15 +43,15 @@ public class SecretOwnerTaskImpl implements SecretOwnerTask { @Override public void start(Observer observer, InetAddress inetAddress) { + this.observer = observer; if (inetAddress == null) observer.onStateChanged(new State.Failure()); System.out.println("InetAddress is " + inetAddress); - socketAddress = new InetSocketAddress(inetAddress, 3002); + socketAddress = new InetSocketAddress(inetAddress, PORT); // start listening on socketAddress - ServerSocket ss = null; try { - ss = new ServerSocket(); - ss.bind(socketAddress); + serverSocket = new ServerSocket(); + serverSocket.bind(socketAddress); } catch (IOException e) { observer.onStateChanged(new State.Failure()); // TODO could try incrementing the port number @@ -61,11 +68,36 @@ public class SecretOwnerTaskImpl implements SecretOwnerTask { new State.Listening(clientHelper.toByteArray(payloadList))); } catch (Exception e) { observer.onStateChanged(new State.Failure()); + return; + } + receiveShard(); + } + + private void receiveShard() { + try { + socket = serverSocket.accept(); + observer.onStateChanged(new State.ReceivingShard()); + InputStream inputStream = socket.getInputStream(); + byte[] payloadRaw = new byte[7]; + int read = inputStream.read(payloadRaw); + if (read < 0) throw new IOException("Payload not read"); + System.out.println("payload message: " + new String(payloadRaw)); + OutputStream outputStream = socket.getOutputStream(); + outputStream.write("ack".getBytes()); + serverSocket.close(); + } catch (IOException e) { + observer.onStateChanged(new State.Failure()); } } @Override public void cancel() { cancelled = true; + try { + serverSocket.close(); + } catch (IOException e) { + observer.onStateChanged(new State.Failure()); + } + observer.onStateChanged(new State.Failure()); } } From b07206c89829329e3daad8579fdd4da15d1e711f Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 13 Apr 2021 18:21:55 +0200 Subject: [PATCH 25/48] Improve UI for shard return --- .../android/activity/ActivityComponent.java | 3 + .../DistributedBackupActivity.java | 2 +- .../recover/CustodianReturnShardActivity.java | 7 +- .../CustodianReturnShardSuccessFragment.java | 59 +++++++++ .../CustodianReturnShardViewModel.java | 11 ++ .../recover/OwnerReturnShardActivity.java | 59 +++------ .../recover/OwnerReturnShardViewModel.java | 112 +++--------------- .../fragment_recovery_custodian_done.xml | 11 ++ 8 files changed, 123 insertions(+), 141 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardSuccessFragment.java diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java index e4859d5c8..14213dd10 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java @@ -87,6 +87,7 @@ import org.briarproject.briar.android.socialbackup.DistributedBackupActivity; import org.briarproject.briar.android.socialbackup.ExistingBackupFragment; import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardActivity; import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardFragment; +import org.briarproject.briar.android.socialbackup.recover.CustodianReturnShardSuccessFragment; import org.briarproject.briar.android.socialbackup.recover.OwnerRecoveryModeExplainerFragment; import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardActivity; import org.briarproject.briar.android.socialbackup.recover.OwnerReturnShardFragment; @@ -293,4 +294,6 @@ public interface ActivityComponent { void inject(CustodianReturnShardFragment custodianReturnShardFragment); void inject(OwnerReturnShardFragment ownerReturnShardFragment); + + void inject(CustodianReturnShardSuccessFragment custodianReturnShardSuccessFragment); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/DistributedBackupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/DistributedBackupActivity.java index 4f8b29ea8..35679e565 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/DistributedBackupActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/DistributedBackupActivity.java @@ -61,7 +61,7 @@ public class DistributedBackupActivity extends BriarActivity implements @Override public void contactsSelected(Collection contacts) { Toast.makeText(this, - String.format("selected %d contacts", contacts.size()), + String.format("Selected %d contacts", contacts.size()), Toast.LENGTH_SHORT).show(); custodians = contacts; ThresholdSelectorFragment fragment = diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java index f808a37c3..1f50328dc 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardActivity.java @@ -7,6 +7,7 @@ import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BriarActivity; import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.socialbackup.CustodianRecoveryModeExplainerFragment; +import org.briarproject.briar.android.socialbackup.ShardsSentFragment; import org.briarproject.briar.api.socialbackup.recovery.CustodianTask; import java.util.logging.Logger; @@ -59,13 +60,17 @@ public class CustodianReturnShardActivity extends BriarActivity viewModel.getShowCameraFragment().observeEvent(this, show -> { if (show) showCameraFragment(); }); + viewModel.getSuccessDismissed().observeEvent(this, dismissed -> { + if (dismissed) finish(); + }); viewModel.getState() .observe(this, this::onReturnShardStateChanged); } private void onReturnShardStateChanged(CustodianTask.State state) { if (state instanceof CustodianTask.State.Success) { - + CustodianReturnShardSuccessFragment fragment = new CustodianReturnShardSuccessFragment(); + showNextFragment(fragment); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardSuccessFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardSuccessFragment.java new file mode 100644 index 000000000..b058d1bb7 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardSuccessFragment.java @@ -0,0 +1,59 @@ +package org.briarproject.briar.android.socialbackup.recover; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.briar.R; +import org.briarproject.briar.android.activity.ActivityComponent; +import org.briarproject.briar.android.fragment.BaseFragment; + +import javax.inject.Inject; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.ViewModelProvider; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class CustodianReturnShardSuccessFragment extends + BaseFragment { + + public static final String TAG = + CustodianReturnShardFragment.class.getName(); + + @Inject + ViewModelProvider.Factory viewModelFactory; + + private CustodianReturnShardViewModel viewModel; + + @Override + public void injectFragment(ActivityComponent component) { + component.inject(this); + viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) + .get(CustodianReturnShardViewModel.class); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_recovery_custodian_done, + container, false); + + Button button = view.findViewById(R.id.button); + button.setOnClickListener(e -> viewModel.onSuccessDismissed()); + + return view; + } + + @Override + public String getUniqueTag() { + return TAG; + } +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java index 6cb5a01e3..78c49b3a5 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/CustodianReturnShardViewModel.java @@ -48,6 +48,8 @@ public class CustodianReturnShardViewModel extends AndroidViewModel private boolean qrCodeRead = false; private final MutableLiveEvent showCameraFragment = new MutableLiveEvent<>(); + private final MutableLiveEvent successDismissed = + new MutableLiveEvent<>(); private final MutableLiveData state = new MutableLiveData<>(); final QrCodeDecoder qrCodeDecoder; @@ -100,6 +102,12 @@ public class CustodianReturnShardViewModel extends AndroidViewModel showCameraFragment.setEvent(true); } + @UiThread + public void onSuccessDismissed() { + successDismissed.setEvent(true); + } + + QrCodeDecoder getQrCodeDecoder() { return qrCodeDecoder; } @@ -108,6 +116,9 @@ public class CustodianReturnShardViewModel extends AndroidViewModel return showCameraFragment; } + LiveEvent getSuccessDismissed() { + return successDismissed; + } LiveData getState() { return state; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java index 91770a459..3a29ec53f 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardActivity.java @@ -10,7 +10,6 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BaseActivity; -import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactErrorFragment; import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask; @@ -23,7 +22,6 @@ import androidx.fragment.app.FragmentManager; import androidx.lifecycle.ViewModelProvider; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; -import static android.widget.Toast.LENGTH_LONG; import static java.util.logging.Logger.getLogger; @MethodsNotNullByDefault @@ -78,10 +76,6 @@ public class OwnerReturnShardActivity extends BaseActivity if (state == null) { showInitialFragment(new OwnerRecoveryModeExplainerFragment()); } -// viewModel.getCheckPermissions().observeEvent(this, check -> -// permissionManager.checkPermissions()); -// viewModel.getRequestBluetoothDiscoverable().observeEvent(this, r -> -// requestBluetoothDiscoverable()); // never false viewModel.getShowQrCodeFragment().observeEvent(this, show -> { if (show) showQrCodeFragment(); }); @@ -117,6 +111,7 @@ public class OwnerReturnShardActivity extends BaseActivity @Override public void onBackPressed() { + // TODO should we cancel the return shard task here? if (viewModel.getState() .getValue() instanceof SecretOwnerTask.State.Failure) { // re-create this activity when going back in failed state @@ -141,47 +136,23 @@ public class OwnerReturnShardActivity extends BaseActivity } private void onReturnShardStateChanged(SecretOwnerTask.State state) { -// if (state instanceof ReturnShardState.SocialBackupExchangeFinished) { -// ReturnShardState.SocialBackupExchangeResult result = -// ((ReturnShardState.SocialBackupExchangeFinished) state).result; -// onSocialBackupExchangeResult(result); -// } else if (state instanceof ReturnShardState.Failed) { -// Boolean qrCodeTooOld = -// ((ReturnShardState.Failed) state).qrCodeTooOld; -// onAddingContactFailed(qrCodeTooOld); -// } - } - - private void onSocialBackupExchangeResult( - ReturnShardState.SocialBackupExchangeResult result) { - if (result instanceof ReturnShardState.SocialBackupExchangeResult.Success) { -// String text = getString(R.string.contact_added_toast, contactName); - Toast.makeText(this, "Shard return successful", LENGTH_LONG).show(); - supportFinishAfterTransition(); - } else if (result instanceof ReturnShardState.SocialBackupExchangeResult.Error) { - showErrorFragment(); - } else throw new AssertionError(); - } - - private void onAddingContactFailed(@Nullable Boolean qrCodeTooOld) { - if (qrCodeTooOld == null) { - showErrorFragment(); - } else { - String msg; - if (qrCodeTooOld) { - msg = getString(R.string.qr_code_too_old, - getString(R.string.app_name)); - } else { - msg = getString(R.string.qr_code_too_new, - getString(R.string.app_name)); - } - showNextFragment(AddNearbyContactErrorFragment.newInstance(msg)); + if (state instanceof SecretOwnerTask.State.Success) { + Toast.makeText(this, + "Success - got shard", + Toast.LENGTH_SHORT).show(); + finish(); + } else if (state instanceof SecretOwnerTask.State.Failure) { + Toast.makeText(this, + "Shard return failed!", + Toast.LENGTH_SHORT).show(); + finish(); } } - private void showErrorFragment() { - showNextFragment(new AddNearbyContactErrorFragment()); - } +// private void showErrorFragment() { +// // TODO change this for an appropriate error message fragment +// showNextFragment(new AddNearbyContactErrorFragment()); +// } @Override @Deprecated diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java index 6d9b4f130..28be28d61 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/OwnerReturnShardViewModel.java @@ -136,91 +136,12 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT @UiThread private void stopListening() { - task.cancel(); -// KeyAgreementTask oldTask = task; -// ioExecutor.execute(() -> { -// if (oldTask != null) oldTask.stopListening(); -// }); + ioExecutor.execute(() -> { + task.cancel(); + }); } -// @Override -// public void eventOccurred(Event e) { -// if (e instanceof TransportStateEvent) { -// TransportStateEvent t = (TransportStateEvent) e; -// if (t.getTransportId().equals(BluetoothConstants.ID)) { -// if (LOG.isLoggable(INFO)) { -// LOG.info("Bluetooth state changed to " + t.getState()); -// } -// showQrCodeFragmentIfAllowed(); -// } else if (t.getTransportId().equals(LanTcpConstants.ID)) { -// if (LOG.isLoggable(INFO)) { -// LOG.info("Wifi state changed to " + t.getState()); -// } -// showQrCodeFragmentIfAllowed(); -// } -// } else if (e instanceof KeyAgreementListeningEvent) { -// LOG.info("KeyAgreementListeningEvent received"); -// KeyAgreementListeningEvent event = (KeyAgreementListeningEvent) e; -// onLocalPayloadReceived(event.getLocalPayload()); -// } else if (e instanceof KeyAgreementWaitingEvent) { -// LOG.info("KeyAgreementWaitingEvent received"); -// state.setValue(new ReturnShardState.KeyAgreementWaiting()); -// } else if (e instanceof KeyAgreementStartedEvent) { -// LOG.info("KeyAgreementStartedEvent received"); -// state.setValue(new ReturnShardState.KeyAgreementStarted()); -// } else if (e instanceof KeyAgreementFinishedEvent) { -// LOG.info("KeyAgreementFinishedEvent received"); -// KeyAgreementResult result = -// ((KeyAgreementFinishedEvent) e).getResult(); -// startContactExchange(result); -// state.setValue(new ReturnShardState.SocialBackupExchangeStarted()); -// } else if (e instanceof KeyAgreementAbortedEvent) { -// LOG.info("KeyAgreementAbortedEvent received"); -// resetPayloadFlags(); -// state.setValue(new ReturnShardState.Failed()); -// } else if (e instanceof KeyAgreementFailedEvent) { -// LOG.info("KeyAgreementFailedEvent received"); -// resetPayloadFlags(); -// state.setValue(new ReturnShardState.Failed()); -// } -// } - @UiThread -// private void startContactExchange(KeyAgreementResult result) { -// TransportId t = result.getTransportId(); -// DuplexTransportConnection conn = result.getConnection(); -// SecretKey masterKey = result.getMasterKey(); -// boolean alice = result.wasAlice(); -// ioExecutor.execute(() -> { -// try { -// if (sending) { -// socialBackupExchangeManager.sendReturnShard(conn, masterKey, alice, returnShardPayload); -// } else { -// returnShardPayload = socialBackupExchangeManager.receiveReturnShard(conn, masterKey, alice); -// } -// ReturnShardState.SocialBackupExchangeResult.Success -// success = -// new ReturnShardState.SocialBackupExchangeResult.Success(); -// state.postValue( -// new ReturnShardState.SocialBackupExchangeFinished(success)); -// } catch (ContactExistsException e) { -// tryToClose(conn); -// ReturnShardState.SocialBackupExchangeResult.Error -// error = new ReturnShardState.SocialBackupExchangeResult.Error( -// e.getRemoteAuthor()); -// state.postValue( -// new ReturnShardState.SocialBackupExchangeFinished(error)); -// } catch (DbException | IOException e) { -// tryToClose(conn); -// logException(LOG, WARNING, e); -// ReturnShardState.SocialBackupExchangeResult.Error -// error = -// new ReturnShardState.SocialBackupExchangeResult.Error(null); -// state.postValue( -// new ReturnShardState.SocialBackupExchangeFinished(error)); -// } -// }); -// } /** @@ -252,18 +173,19 @@ class OwnerReturnShardViewModel extends AndroidViewModel implements SecretOwnerT @Override public void onStateChanged(SecretOwnerTask.State state) { - if (state instanceof SecretOwnerTask.State.Listening) { - DisplayMetrics dm = getApplication().getResources().getDisplayMetrics(); - ioExecutor.execute(() -> { - byte[] payloadBytes = ((SecretOwnerTask.State.Listening) state).getLocalPayload(); - if (LOG.isLoggable(INFO)) { - LOG.info("Local payload is " + payloadBytes.length - + " bytes"); - } - // Use ISO 8859-1 to encode bytes directly as a string - String content = new String(payloadBytes, ISO_8859_1); - qrCodeBitmap = QrCodeUtils.createQrCode(dm, content); - }); - } + this.state.postValue(state); + if (state instanceof SecretOwnerTask.State.Listening) { + DisplayMetrics dm = getApplication().getResources().getDisplayMetrics(); + ioExecutor.execute(() -> { + byte[] payloadBytes = ((SecretOwnerTask.State.Listening) state).getLocalPayload(); + if (LOG.isLoggable(INFO)) { + LOG.info("Local payload is " + payloadBytes.length + + " bytes"); + } + // Use ISO 8859-1 to encode bytes directly as a string + String content = new String(payloadBytes, ISO_8859_1); + qrCodeBitmap = QrCodeUtils.createQrCode(dm, content); + }); + } } } diff --git a/briar-android/src/main/res/layout/fragment_recovery_custodian_done.xml b/briar-android/src/main/res/layout/fragment_recovery_custodian_done.xml index eb33d3c90..25b9e72c6 100644 --- a/briar-android/src/main/res/layout/fragment_recovery_custodian_done.xml +++ b/briar-android/src/main/res/layout/fragment_recovery_custodian_done.xml @@ -10,6 +10,17 @@ android:paddingRight="@dimen/margin_large" android:paddingBottom="@dimen/margin_medium"> +