mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-24 08:39:53 +01:00
Compare commits
41 Commits
new-or-rec
...
social-bac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
995a053241 | ||
|
|
265d1da566 | ||
|
|
b6d57a492b | ||
|
|
943f107232 | ||
|
|
09e024ea5e | ||
|
|
2486a60fea | ||
|
|
365fa58928 | ||
|
|
45d2e2ce06 | ||
|
|
b1f5d71a4e | ||
|
|
d47c18b392 | ||
|
|
8ed58eaada | ||
|
|
8478097a3c | ||
|
|
0440c5c7c8 | ||
|
|
58db654a9b | ||
|
|
c3d137a73c | ||
|
|
db7825d7f6 | ||
|
|
24059adbd6 | ||
|
|
7d128988a7 | ||
|
|
9499a078a6 | ||
|
|
6483b0ed87 | ||
|
|
af097dc859 | ||
|
|
3adc6d002c | ||
|
|
0658e90c65 | ||
|
|
6d0aebd7ec | ||
|
|
0faccfe5a3 | ||
|
|
c19c40bdc8 | ||
|
|
363da96709 | ||
|
|
e9c2cb2cc5 | ||
|
|
505124a22f | ||
|
|
9b750291d1 | ||
|
|
9c829ec7c9 | ||
|
|
1b9ba41110 | ||
|
|
fa39e7c824 | ||
|
|
37fb3bd79f | ||
|
|
1c5e89b100 | ||
|
|
6dc6a34d29 | ||
|
|
35b2b8c9d2 | ||
|
|
e3ff8a80e5 | ||
|
|
e09fedd79f | ||
|
|
6c3df2a3d4 | ||
|
|
a9edf43df2 |
@@ -24,7 +24,7 @@ android {
|
|||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 10216
|
versionCode 10216
|
||||||
versionName "1.2.16"
|
versionName "1.2.16"
|
||||||
applicationId "org.briarproject.briar.android"
|
applicationId "org.briarproject.briar.socialbackup"
|
||||||
|
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
buildConfigField "String", "GitHash",
|
buildConfigField "String", "GitHash",
|
||||||
|
|||||||
@@ -40,3 +40,5 @@
|
|||||||
|
|
||||||
# Dependency injection annotations, needed for UI tests on older API levels
|
# Dependency injection annotations, needed for UI tests on older API levels
|
||||||
-keep class javax.inject.**
|
-keep class javax.inject.**
|
||||||
|
|
||||||
|
-keep class com.sun.jna.** { *; }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name" translatable="false">Briar Debug</string>
|
<string name="app_name" translatable="false">Briar SB Debug</string>
|
||||||
<string name="app_package" translatable="false">org.briarproject.briar.android.debug</string>
|
<string name="app_package" translatable="false">org.briarproject.briar.socialbackup.debug</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -153,14 +153,22 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="org.briarproject.briar.android.socialbackup.OldDistributedBackupActivity"
|
android:name="org.briarproject.briar.android.socialbackup.RecoverActivity"
|
||||||
android:label="@string/activity_name_old_distributed_backup"
|
android:label="@string/activity_name_recovery"
|
||||||
android:parentActivityName="org.briarproject.briar.android.settings.SettingsActivity">
|
android:parentActivityName="org.briarproject.briar.android.account.NewOrRecoverActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="org.briarproject.briar.android.settings.SettingsActivity" />
|
android:value="org.briarproject.briar.android.account.NewOrRecoverActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="org.briarproject.briar.android.socialbackup.CustodianHelpRecoverActivity"
|
||||||
|
android:label="@string/activity_name_custodian_help_recovery"
|
||||||
|
android:parentActivityName="org.briarproject.briar.android.conversation.ConversationActivity">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
|
android:value="org.briarproject.briar.android.conversation.ConversationActivity" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="org.briarproject.briar.android.conversation.ConversationActivity"
|
android:name="org.briarproject.briar.android.conversation.ConversationActivity"
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ public interface AndroidComponent
|
|||||||
Thread.UncaughtExceptionHandler exceptionHandler();
|
Thread.UncaughtExceptionHandler exceptionHandler();
|
||||||
|
|
||||||
SocialBackupManager socialBackupManager();
|
SocialBackupManager socialBackupManager();
|
||||||
|
|
||||||
DatabaseComponent databaseComponent();
|
DatabaseComponent databaseComponent();
|
||||||
|
|
||||||
void inject(SignInReminderReceiver briarService);
|
void inject(SignInReminderReceiver briarService);
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import org.briarproject.briar.api.android.DozeWatchdog;
|
|||||||
import org.briarproject.briar.api.android.LockManager;
|
import org.briarproject.briar.api.android.LockManager;
|
||||||
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
||||||
import org.briarproject.briar.api.test.TestAvatarCreator;
|
import org.briarproject.briar.api.test.TestAvatarCreator;
|
||||||
|
import org.briarproject.briar.socialbackup.AndroidDarkCrystalModule;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
@@ -82,6 +83,7 @@ import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
|||||||
SettingsModule.class,
|
SettingsModule.class,
|
||||||
DevReportModule.class,
|
DevReportModule.class,
|
||||||
ContactListModule.class,
|
ContactListModule.class,
|
||||||
|
AndroidDarkCrystalModule.class,
|
||||||
// below need to be within same scope as ViewModelProvider.Factory
|
// below need to be within same scope as ViewModelProvider.Factory
|
||||||
ForumModule.class,
|
ForumModule.class,
|
||||||
GroupListModule.class,
|
GroupListModule.class,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import org.briarproject.briar.R;
|
|||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BaseActivity;
|
import org.briarproject.briar.android.activity.BaseActivity;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
|
import org.briarproject.briar.android.socialbackup.RecoverActivity;
|
||||||
|
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||||
@@ -14,7 +15,8 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
|||||||
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
|
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
|
||||||
|
|
||||||
public class NewOrRecoverActivity extends BaseActivity implements
|
public class NewOrRecoverActivity extends BaseActivity implements
|
||||||
BaseFragment.BaseFragmentListener, SetupNewAccountChosenListener {
|
BaseFragment.BaseFragmentListener, SetupNewAccountChosenListener,
|
||||||
|
RecoverAccountListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectActivity(ActivityComponent component) {
|
public void injectActivity(ActivityComponent component) {
|
||||||
@@ -26,13 +28,13 @@ public class NewOrRecoverActivity extends BaseActivity implements
|
|||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
// fade-in after splash screen instead of default animation
|
// fade-in after splash screen instead of default animation
|
||||||
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
|
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
|
||||||
setContentView(R.layout.activity_fragment_container);
|
setContentView(R.layout.activity_fragment_container);
|
||||||
NewOrRecoverFragment fragment = NewOrRecoverFragment.newInstance();
|
NewOrRecoverFragment fragment = NewOrRecoverFragment.newInstance();
|
||||||
showInitialFragment(fragment);
|
showInitialFragment(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setupNewAccountChosen () {
|
public void setupNewAccountChosen() {
|
||||||
finish();
|
finish();
|
||||||
Intent i = new Intent(this, SetupActivity.class);
|
Intent i = new Intent(this, SetupActivity.class);
|
||||||
i.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
|
i.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
|
||||||
@@ -41,7 +43,17 @@ public class NewOrRecoverActivity extends BaseActivity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void runOnDbThread(Runnable runnable) {
|
public void recoverAccountChosen() {
|
||||||
|
finish();
|
||||||
|
Intent i = new Intent(this, RecoverActivity.class);
|
||||||
|
i.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
|
||||||
|
FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_TASK_ON_HOME);
|
||||||
|
startActivity(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void runOnDbThread(Runnable runnable) {
|
||||||
|
throw new RuntimeException("Don't use this deprecated method here.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ public class NewOrRecoverFragment extends BaseFragment {
|
|||||||
|
|
||||||
public static final String TAG = NewOrRecoverFragment.class.getName();
|
public static final String TAG = NewOrRecoverFragment.class.getName();
|
||||||
|
|
||||||
protected SetupNewAccountChosenListener listener;
|
protected SetupNewAccountChosenListener setupNewAccountListener;
|
||||||
|
protected RecoverAccountListener recoverAccountListener;
|
||||||
|
|
||||||
public static NewOrRecoverFragment newInstance() {
|
public static NewOrRecoverFragment newInstance() {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
@@ -38,9 +39,14 @@ public class NewOrRecoverFragment extends BaseFragment {
|
|||||||
ViewGroup container, @Nullable Bundle savedInstanceState) {
|
ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.fragment_new_or_recover,
|
View view = inflater.inflate(R.layout.fragment_new_or_recover,
|
||||||
container, false);
|
container, false);
|
||||||
Button button = view.findViewById(R.id.buttonSetupNewAccount);
|
Button newAccountButton = view.findViewById(R.id.buttonSetupNewAccount);
|
||||||
button.setOnClickListener(e -> {
|
newAccountButton.setOnClickListener(e -> {
|
||||||
listener.setupNewAccountChosen();
|
setupNewAccountListener.setupNewAccountChosen();
|
||||||
|
});
|
||||||
|
|
||||||
|
Button recoverAccountButton = view.findViewById(R.id.buttonRestoreAccount);
|
||||||
|
recoverAccountButton.setOnClickListener(e -> {
|
||||||
|
recoverAccountListener.recoverAccountChosen();
|
||||||
});
|
});
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
@@ -48,7 +54,8 @@ public class NewOrRecoverFragment extends BaseFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onAttach(Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
listener = (SetupNewAccountChosenListener) context;
|
setupNewAccountListener = (SetupNewAccountChosenListener) context;
|
||||||
|
recoverAccountListener = (RecoverAccountListener) context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.briarproject.briar.android.account;
|
||||||
|
|
||||||
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
|
public interface RecoverAccountListener {
|
||||||
|
@UiThread
|
||||||
|
void recoverAccountChosen();
|
||||||
|
}
|
||||||
@@ -81,17 +81,18 @@ import org.briarproject.briar.android.sharing.ShareForumActivity;
|
|||||||
import org.briarproject.briar.android.sharing.ShareForumFragment;
|
import org.briarproject.briar.android.sharing.ShareForumFragment;
|
||||||
import org.briarproject.briar.android.sharing.SharingModule;
|
import org.briarproject.briar.android.sharing.SharingModule;
|
||||||
//import org.briarproject.briar.android.socialbackup.CustodianDisplayFragment;
|
//import org.briarproject.briar.android.socialbackup.CustodianDisplayFragment;
|
||||||
|
import org.briarproject.briar.android.socialbackup.CustodianHelpRecoverActivity;
|
||||||
import org.briarproject.briar.android.socialbackup.CustodianSelectorFragment;
|
import org.briarproject.briar.android.socialbackup.CustodianSelectorFragment;
|
||||||
import org.briarproject.briar.android.socialbackup.DistributedBackupActivity;
|
import org.briarproject.briar.android.socialbackup.DistributedBackupActivity;
|
||||||
import org.briarproject.briar.android.socialbackup.ExistingBackupFragment;
|
import org.briarproject.briar.android.socialbackup.ExistingBackupFragment;
|
||||||
import org.briarproject.briar.android.socialbackup.OldDistributedBackupActivity;
|
import org.briarproject.briar.android.socialbackup.OwnerRecoveryModeExplainerFragment;
|
||||||
|
import org.briarproject.briar.android.socialbackup.RecoverActivity;
|
||||||
|
import org.briarproject.briar.android.socialbackup.ShardQrCodeFragment;
|
||||||
import org.briarproject.briar.android.socialbackup.ShardsSentFragment;
|
import org.briarproject.briar.android.socialbackup.ShardsSentFragment;
|
||||||
import org.briarproject.briar.android.socialbackup.ThresholdSelectorFragment;
|
import org.briarproject.briar.android.socialbackup.ThresholdSelectorFragment;
|
||||||
import org.briarproject.briar.android.socialbackup.creation.CreateBackupController;
|
|
||||||
import org.briarproject.briar.android.socialbackup.creation.CreateBackupModule;
|
import org.briarproject.briar.android.socialbackup.creation.CreateBackupModule;
|
||||||
import org.briarproject.briar.android.splash.SplashScreenActivity;
|
import org.briarproject.briar.android.splash.SplashScreenActivity;
|
||||||
import org.briarproject.briar.android.test.TestDataActivity;
|
import org.briarproject.briar.android.test.TestDataActivity;
|
||||||
import org.h2.util.New;
|
|
||||||
|
|
||||||
import dagger.Component;
|
import dagger.Component;
|
||||||
|
|
||||||
@@ -198,6 +199,8 @@ public interface ActivityComponent {
|
|||||||
|
|
||||||
void inject(NewOrRecoverActivity newOrRecoverActivity);
|
void inject(NewOrRecoverActivity newOrRecoverActivity);
|
||||||
|
|
||||||
|
void inject(CustodianHelpRecoverActivity custodianHelpRecoverActivity);
|
||||||
|
|
||||||
// Fragments
|
// Fragments
|
||||||
|
|
||||||
void inject(AuthorNameFragment fragment);
|
void inject(AuthorNameFragment fragment);
|
||||||
@@ -256,9 +259,11 @@ public interface ActivityComponent {
|
|||||||
|
|
||||||
void inject(ThresholdSelectorFragment thresholdSelectorFragment);
|
void inject(ThresholdSelectorFragment thresholdSelectorFragment);
|
||||||
|
|
||||||
|
void inject(ShardQrCodeFragment shardQrCodeFragment);
|
||||||
|
|
||||||
void inject(DistributedBackupActivity distributedBackupActivity);
|
void inject(DistributedBackupActivity distributedBackupActivity);
|
||||||
// void inject(CreateBackupController createBackupController);
|
|
||||||
// void inject(CustodianDisplayFragment custodianDisplayFragment);
|
void inject(RecoverActivity recoverActivity);
|
||||||
|
|
||||||
void inject(DatabaseComponent databaseComponent);
|
void inject(DatabaseComponent databaseComponent);
|
||||||
|
|
||||||
@@ -266,9 +271,9 @@ public interface ActivityComponent {
|
|||||||
|
|
||||||
void inject(ShardsSentFragment shardsSentFragment);
|
void inject(ShardsSentFragment shardsSentFragment);
|
||||||
|
|
||||||
|
void inject(OwnerRecoveryModeExplainerFragment ownerRecoveryModeExplainerFragment);
|
||||||
|
|
||||||
void inject(ExistingBackupFragment existingBackupFragment);
|
void inject(ExistingBackupFragment existingBackupFragment);
|
||||||
|
|
||||||
void inject(NewOrRecoverFragment newOrRecoverFragment);
|
void inject(NewOrRecoverFragment newOrRecoverFragment);
|
||||||
|
|
||||||
void inject(OldDistributedBackupActivity oldDistributedBackupActivity);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import org.briarproject.briar.android.conversation.ConversationVisitor.TextCache
|
|||||||
import org.briarproject.briar.android.forum.ForumActivity;
|
import org.briarproject.briar.android.forum.ForumActivity;
|
||||||
import org.briarproject.briar.android.introduction.IntroductionActivity;
|
import org.briarproject.briar.android.introduction.IntroductionActivity;
|
||||||
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
||||||
|
import org.briarproject.briar.android.socialbackup.CustodianHelpRecoverActivity;
|
||||||
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
||||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||||
import org.briarproject.briar.android.view.ImagePreview;
|
import org.briarproject.briar.android.view.ImagePreview;
|
||||||
@@ -396,6 +397,12 @@ public class ConversationActivity extends BriarActivity
|
|||||||
case R.id.action_social_remove_person:
|
case R.id.action_social_remove_person:
|
||||||
askToRemoveContact();
|
askToRemoveContact();
|
||||||
return true;
|
return true;
|
||||||
|
case R.id.action_help_recover_account:
|
||||||
|
if (contactId == null) return false;
|
||||||
|
Intent i = new Intent(this, CustodianHelpRecoverActivity.class);
|
||||||
|
i.putExtra(CONTACT_ID, contactId.getInt());
|
||||||
|
startActivity(i);
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.briar.android.conversation;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.briar.api.conversation.ConversationRequest;
|
import org.briarproject.briar.api.conversation.ConversationRequest;
|
||||||
import org.briarproject.briar.api.conversation.ConversationResponse;
|
import org.briarproject.briar.api.conversation.ConversationResponse;
|
||||||
|
import org.briarproject.briar.api.socialbackup.ShardMessageHeader;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
@@ -30,6 +31,13 @@ class ConversationNoticeItem extends ConversationItem {
|
|||||||
this.msgText = null;
|
this.msgText = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConversationNoticeItem(@LayoutRes int layoutRes, String text,
|
||||||
|
ShardMessageHeader r) {
|
||||||
|
super(layoutRes, r);
|
||||||
|
this.text = text;
|
||||||
|
this.msgText = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
String getMsgText() {
|
String getMsgText() {
|
||||||
return msgText;
|
return msgText;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.briarproject.briar.api.introduction.IntroductionResponse;
|
|||||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
|
||||||
|
import org.briarproject.briar.api.socialbackup.ShardMessageHeader;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -292,6 +293,19 @@ class ConversationVisitor implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversationItem visitShardMessage(ShardMessageHeader r) {
|
||||||
|
if (r.isLocal()) {
|
||||||
|
String text = ctx.getString(R.string.social_backup_shard_sent);
|
||||||
|
return new ConversationNoticeItem(
|
||||||
|
R.layout.list_item_conversation_notice_out, text, r);
|
||||||
|
} else {
|
||||||
|
String text = ctx.getString(R.string.social_backup_shard_received);
|
||||||
|
return new ConversationNoticeItem(
|
||||||
|
R.layout.list_item_conversation_notice_in, text, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface TextCache {
|
interface TextCache {
|
||||||
@Nullable
|
@Nullable
|
||||||
String getText(MessageId m);
|
String getText(MessageId m);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package org.briarproject.briar.android.keyagreement;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
class CameraException extends IOException {
|
public class CameraException extends IOException {
|
||||||
|
|
||||||
CameraException(String message) {
|
CameraException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import static java.util.logging.Level.WARNING;
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
|
public class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(QrCodeDecoder.class.getName());
|
Logger.getLogger(QrCodeDecoder.class.getName());
|
||||||
@@ -41,7 +41,7 @@ class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
|
|||||||
private Camera camera = null;
|
private Camera camera = null;
|
||||||
private int cameraIndex = 0;
|
private int cameraIndex = 0;
|
||||||
|
|
||||||
QrCodeDecoder(ResultCallback callback) {
|
public QrCodeDecoder(ResultCallback callback) {
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
interface ResultCallback {
|
public interface ResultCallback {
|
||||||
|
|
||||||
void handleResult(Result result);
|
void handleResult(Result result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ import static java.util.logging.Level.WARNING;
|
|||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class QrCodeUtils {
|
public class QrCodeUtils {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(QrCodeUtils.class.getName());
|
Logger.getLogger(QrCodeUtils.class.getName());
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
static Bitmap createQrCode(DisplayMetrics dm, String input) {
|
public static Bitmap createQrCode(DisplayMetrics dm, String input) {
|
||||||
int smallestDimen = Math.min(dm.widthPixels, dm.heightPixels);
|
int smallestDimen = Math.min(dm.widthPixels, dm.heightPixels);
|
||||||
try {
|
try {
|
||||||
// Generate QR code
|
// Generate QR code
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package org.briarproject.briar.android.socialbackup;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
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.api.socialbackup.SocialBackupManager;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID;
|
||||||
|
|
||||||
|
public class CustodianHelpRecoverActivity extends BriarActivity implements
|
||||||
|
BaseFragment.BaseFragmentListener, CustodianScanQrButtonListener {
|
||||||
|
@Override
|
||||||
|
public void injectActivity(ActivityComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public SocialBackupManager socialBackupManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public DatabaseComponent db;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_recover); // TODO change this
|
||||||
|
|
||||||
|
Intent intent = getIntent();
|
||||||
|
int id = intent.getIntExtra(CONTACT_ID, -1);
|
||||||
|
if (id == -1) throw new IllegalStateException("No ContactId");
|
||||||
|
ContactId contactId = new ContactId(id);
|
||||||
|
|
||||||
|
// check if we have a shard for this secret owner
|
||||||
|
try {
|
||||||
|
db.transaction(false, txn -> {
|
||||||
|
if (!socialBackupManager.amCustodian(txn, contactId)) {
|
||||||
|
throw new DbException();
|
||||||
|
}
|
||||||
|
CustodianRecoveryModeExplainerFragment fragment =
|
||||||
|
new CustodianRecoveryModeExplainerFragment();
|
||||||
|
showInitialFragment(fragment);
|
||||||
|
});
|
||||||
|
} catch (DbException e) {
|
||||||
|
// TODO improve this
|
||||||
|
Toast.makeText(this,
|
||||||
|
"You do not hold a backup shard from this contact",
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scanQrButtonClicked() {
|
||||||
|
// TODO scan qr code
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
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.android.fragment.BaseFragment;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
|
public class CustodianRecoveryModeExplainerFragment extends BaseFragment {
|
||||||
|
|
||||||
|
protected CustodianScanQrButtonListener listener;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
|
||||||
|
Button button = view.findViewById(R.id.button);
|
||||||
|
button.setOnClickListener(e -> listener.scanQrButtonClicked());
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
listener = (CustodianScanQrButtonListener) context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUniqueTag() {
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.briarproject.briar.android.socialbackup;
|
||||||
|
|
||||||
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
|
public interface CustodianScanQrButtonListener {
|
||||||
|
@UiThread
|
||||||
|
void scanQrButtonClicked();
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.briar.android.socialbackup;
|
package org.briarproject.briar.android.socialbackup;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.briar.api.socialbackup.Shard;
|
import org.briarproject.briar.api.socialbackup.Shard;
|
||||||
import org.briarproject.briar.api.socialbackup.DarkCrystal;
|
import org.briarproject.briar.api.socialbackup.DarkCrystal;
|
||||||
import org.magmacollective.darkcrystal.secretsharingwrapper.SecretSharingWrapper;
|
import org.magmacollective.darkcrystal.secretsharingwrapper.SecretSharingWrapper;
|
||||||
@@ -10,10 +11,19 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
import static org.briarproject.briar.socialbackup.SocialBackupConstants.SECRET_ID_BYTES;
|
import static org.briarproject.briar.socialbackup.SocialBackupConstants.SECRET_ID_BYTES;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
public class DarkCrystalImpl implements DarkCrystal {
|
public class DarkCrystalImpl implements DarkCrystal {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
DarkCrystalImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Shard> createShards(SecretKey secret, int numShards,
|
public List<Shard> createShards(SecretKey secret, int numShards,
|
||||||
int threshold) {
|
int threshold) {
|
||||||
|
|||||||
@@ -21,15 +21,16 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
public class DistributedBackupActivity extends BriarActivity implements
|
public class DistributedBackupActivity extends BriarActivity implements
|
||||||
BaseFragment.BaseFragmentListener, ContactSelectorListener,
|
BaseFragment.BaseFragmentListener, ContactSelectorListener,
|
||||||
ThresholdDefinedListener, ShardsSentDismissedListener {
|
ThresholdDefinedListener,
|
||||||
|
ShardsSentFragment.ShardsSentDismissedListener {
|
||||||
|
|
||||||
private Collection<ContactId> custodians;
|
private Collection<ContactId> custodians;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public SocialBackupManager socialBackupManager;
|
public SocialBackupManager socialBackupManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public DatabaseComponent db;
|
public DatabaseComponent db;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectActivity(ActivityComponent component) {
|
public void injectActivity(ActivityComponent component) {
|
||||||
@@ -40,22 +41,20 @@ public class DistributedBackupActivity extends BriarActivity implements
|
|||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_distributed_backup);
|
setContentView(R.layout.activity_distributed_backup);
|
||||||
// TODO here we should check if we already have a backup
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.transaction(false, txn -> {
|
db.transaction(false, txn -> {
|
||||||
BackupMetadata backupMetadata = socialBackupManager.getBackupMetadata(txn);
|
BackupMetadata backupMetadata =
|
||||||
if (backupMetadata == null) {
|
socialBackupManager.getBackupMetadata(txn);
|
||||||
CustodianSelectorFragment fragment =
|
if (backupMetadata == null) throw new DbException();
|
||||||
CustodianSelectorFragment.newInstance();
|
ExistingBackupFragment fragment =
|
||||||
showInitialFragment(fragment);
|
ExistingBackupFragment.newInstance(backupMetadata);
|
||||||
} else {
|
showInitialFragment(fragment);
|
||||||
ExistingBackupFragment fragment = ExistingBackupFragment.newInstance(backupMetadata);
|
|
||||||
showInitialFragment(fragment);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
e.printStackTrace();
|
CustodianSelectorFragment fragment =
|
||||||
|
CustodianSelectorFragment.newInstance();
|
||||||
|
showInitialFragment(fragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,17 +64,24 @@ public class DistributedBackupActivity extends BriarActivity implements
|
|||||||
String.format("selected %d contacts", contacts.size()),
|
String.format("selected %d contacts", contacts.size()),
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
custodians = contacts;
|
custodians = contacts;
|
||||||
ThresholdSelectorFragment fragment = ThresholdSelectorFragment.newInstance(contacts.size());
|
ThresholdSelectorFragment fragment =
|
||||||
|
ThresholdSelectorFragment.newInstance(contacts.size());
|
||||||
showNextFragment(fragment);
|
showNextFragment(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void thresholdDefined(int threshold) throws DbException {
|
public void thresholdDefined(int threshold) {
|
||||||
db.transaction(false, txn -> {
|
try {
|
||||||
socialBackupManager.createBackup(txn, (List<ContactId>) custodians, threshold);
|
db.transaction(false, txn -> {
|
||||||
ShardsSentFragment fragment = new ShardsSentFragment();
|
socialBackupManager
|
||||||
showNextFragment(fragment);
|
.createBackup(txn, (List<ContactId>) custodians,
|
||||||
});
|
threshold);
|
||||||
|
ShardsSentFragment fragment = new ShardsSentFragment();
|
||||||
|
showNextFragment(fragment);
|
||||||
|
});
|
||||||
|
} catch (DbException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ package org.briarproject.briar.android.socialbackup;
|
|||||||
|
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
public interface ShardsSentDismissedListener {
|
public interface ExplainerDismissedListener {
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
void shardsSentDismissed();
|
void explainerDismissed();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package org.briarproject.briar.android.socialbackup;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.briar.R;
|
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
|
||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
|
||||||
import org.briarproject.briar.android.contactselection.ContactSelectorListener;
|
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
public class OldDistributedBackupActivity extends BriarActivity
|
|
||||||
implements BaseFragment.BaseFragmentListener, ContactSelectorListener {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void injectActivity(ActivityComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_distributed_backup);
|
|
||||||
|
|
||||||
// CustodianDisplayFragment fragment =
|
|
||||||
// CustodianDisplayFragment.newInstance();
|
|
||||||
//
|
|
||||||
// showInitialFragment(fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void contactsSelected(Collection<ContactId> contacts) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
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 androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
public class OwnerRecoveryModeExplainerFragment extends BaseFragment {
|
||||||
|
|
||||||
|
protected ExplainerDismissedListener listener;
|
||||||
|
public static final String TAG =
|
||||||
|
OwnerRecoveryModeExplainerFragment.class.getName();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
requireActivity().setTitle(R.string.title_recovery_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||||
|
@Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_recovery_owner_explainer,
|
||||||
|
container, false);
|
||||||
|
Button button = view.findViewById(R.id.beginButton);
|
||||||
|
button.setOnClickListener(e -> listener.explainerDismissed());
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
listener = (ExplainerDismissedListener) context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void injectFragment(ActivityComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUniqueTag() {
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
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 android.widget.TextView;
|
||||||
|
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
public class OwnerRecoveryModeMainFragment extends BaseFragment {
|
||||||
|
|
||||||
|
protected ScanQrButtonListener listener;
|
||||||
|
|
||||||
|
public static final String NUM_RECOVERED = "num_recovered";
|
||||||
|
|
||||||
|
public static final String TAG =
|
||||||
|
OwnerRecoveryModeMainFragment.class.getName();
|
||||||
|
|
||||||
|
public static OwnerRecoveryModeMainFragment newInstance(int numRecovered) {
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putInt(NUM_RECOVERED, numRecovered);
|
||||||
|
OwnerRecoveryModeMainFragment fragment =
|
||||||
|
new OwnerRecoveryModeMainFragment();
|
||||||
|
fragment.setArguments(args);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int numShards;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUniqueTag() {
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
requireActivity().setTitle(R.string.title_recovery_mode);
|
||||||
|
|
||||||
|
Bundle args = requireArguments();
|
||||||
|
numShards = args.getInt(NUM_RECOVERED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||||
|
@Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_recovery_owner_main,
|
||||||
|
container, false);
|
||||||
|
|
||||||
|
TextView textViewCount = view.findViewById(R.id.textViewShardCount);
|
||||||
|
textViewCount.setText(String.format("%d", numShards));
|
||||||
|
|
||||||
|
Button button = view.findViewById(R.id.button);
|
||||||
|
button.setOnClickListener(e -> listener.scanQrButtonClicked());
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
listener = (ScanQrButtonListener) context;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
package org.briarproject.briar.android.socialbackup;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementResult;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
|
import org.briarproject.briar.android.activity.BaseActivity;
|
||||||
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import androidx.annotation.UiThread;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.CAMERA;
|
||||||
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PERMISSION_CAMERA_LOCATION;
|
||||||
|
|
||||||
|
public class RecoverActivity extends BaseActivity implements
|
||||||
|
BaseFragment.BaseFragmentListener, ExplainerDismissedListener,
|
||||||
|
ScanQrButtonListener, ShardQrCodeFragment.ShardQrCodeEventListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyAgreementFailed() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String keyAgreementWaiting() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String keyAgreementStarted() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyAgreementAborted(boolean remoteAborted) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String keyAgreementFinished(KeyAgreementResult result) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum Permission {
|
||||||
|
UNKNOWN, GRANTED, SHOW_RATIONALE, PERMANENTLY_DENIED
|
||||||
|
}
|
||||||
|
|
||||||
|
private Permission cameraPermission = Permission.UNKNOWN;
|
||||||
|
|
||||||
|
|
||||||
|
private int numRecovered;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_recover);
|
||||||
|
|
||||||
|
numRecovered = 0; // TODO - retrieve this from somewhere
|
||||||
|
|
||||||
|
// only show the explainer if we have no shards
|
||||||
|
if (numRecovered == 0) {
|
||||||
|
OwnerRecoveryModeExplainerFragment fragment =
|
||||||
|
new OwnerRecoveryModeExplainerFragment();
|
||||||
|
showInitialFragment(fragment);
|
||||||
|
} else {
|
||||||
|
OwnerRecoveryModeMainFragment fragment =
|
||||||
|
OwnerRecoveryModeMainFragment.newInstance(numRecovered);
|
||||||
|
showInitialFragment(fragment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void injectActivity(ActivityComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void explainerDismissed() {
|
||||||
|
OwnerRecoveryModeMainFragment fragment =
|
||||||
|
OwnerRecoveryModeMainFragment.newInstance(numRecovered);
|
||||||
|
showNextFragment(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scanQrButtonClicked() {
|
||||||
|
if (checkPermissions()) showQrCodeFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void showQrCodeFragment() {
|
||||||
|
ShardQrCodeFragment f = ShardQrCodeFragment.newInstance();
|
||||||
|
showNextFragment(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestPermissions() {
|
||||||
|
String[] permissions = new String[] {CAMERA};
|
||||||
|
ActivityCompat.requestPermissions(this, permissions,
|
||||||
|
REQUEST_PERMISSION_CAMERA_LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@UiThread
|
||||||
|
public void onRequestPermissionsResult(int requestCode,
|
||||||
|
String[] permissions, int[] grantResults) {
|
||||||
|
if (requestCode != REQUEST_PERMISSION_CAMERA_LOCATION)
|
||||||
|
throw new AssertionError();
|
||||||
|
if (gotPermission(CAMERA, permissions, grantResults)) {
|
||||||
|
cameraPermission = Permission.GRANTED;
|
||||||
|
} else if (shouldShowRationale(CAMERA)) {
|
||||||
|
cameraPermission = Permission.SHOW_RATIONALE;
|
||||||
|
} else {
|
||||||
|
cameraPermission = Permission.PERMANENTLY_DENIED;
|
||||||
|
}
|
||||||
|
// If a permission dialog has been shown, showing the QR code fragment
|
||||||
|
// on this call path would cause a crash due to
|
||||||
|
// https://code.google.com/p/android/issues/detail?id=190966.
|
||||||
|
// In that case the isResumed flag prevents the fragment from being
|
||||||
|
// shown here, and showQrCodeFragmentIfAllowed() will be called again
|
||||||
|
// from onPostResume().
|
||||||
|
if (checkPermissions()) showQrCodeFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean gotPermission(String permission, String[] permissions,
|
||||||
|
int[] grantResults) {
|
||||||
|
for (int i = 0; i < permissions.length; i++) {
|
||||||
|
if (permission.equals(permissions[i]))
|
||||||
|
return grantResults[i] == PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldShowRationale(String permission) {
|
||||||
|
return ActivityCompat.shouldShowRequestPermissionRationale(this,
|
||||||
|
permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkPermissions() {
|
||||||
|
if (areEssentialPermissionsGranted()) return true;
|
||||||
|
// If an essential permission has been permanently denied, ask the
|
||||||
|
// user to change the setting
|
||||||
|
if (cameraPermission == Permission.PERMANENTLY_DENIED) {
|
||||||
|
Toast.makeText(this,
|
||||||
|
"camera permission is denied",
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
// showDenialDialog(R.string.permission_camera_title,
|
||||||
|
// R.string.permission_camera_denied_body);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (cameraPermission == Permission.SHOW_RATIONALE) {
|
||||||
|
// showRationale(R.string.permission_camera_title,
|
||||||
|
// R.string.permission_camera_request_body);
|
||||||
|
Toast.makeText(this,
|
||||||
|
"camera permission - show rationale",
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
requestPermissions();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void runOnDbThread(Runnable runnable) {
|
||||||
|
throw new RuntimeException("Don't use this deprecated method here.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean areEssentialPermissionsGranted() {
|
||||||
|
return cameraPermission == Permission.GRANTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.briarproject.briar.android.socialbackup;
|
||||||
|
|
||||||
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
|
public interface ScanQrButtonListener {
|
||||||
|
@UiThread
|
||||||
|
void scanQrButtonClicked();
|
||||||
|
}
|
||||||
@@ -0,0 +1,381 @@
|
|||||||
|
package org.briarproject.briar.android.socialbackup;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
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 com.google.zxing.Result;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.UnsupportedVersionException;
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementResult;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.Payload;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.PayloadEncoder;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.PayloadParser;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementAbortedEvent;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFailedEvent;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFinishedEvent;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementListeningEvent;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementStartedEvent;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementWaitingEvent;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
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.BaseEventFragment;
|
||||||
|
import org.briarproject.briar.android.keyagreement.CameraException;
|
||||||
|
import org.briarproject.briar.android.keyagreement.CameraView;
|
||||||
|
import org.briarproject.briar.android.keyagreement.ContactExchangeErrorFragment;
|
||||||
|
import org.briarproject.briar.android.keyagreement.QrCodeDecoder;
|
||||||
|
import org.briarproject.briar.android.keyagreement.QrCodeUtils;
|
||||||
|
import org.briarproject.briar.android.view.QrCodeView;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Provider;
|
||||||
|
|
||||||
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
|
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
||||||
|
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.INFO;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
public class ShardQrCodeFragment extends BaseEventFragment
|
||||||
|
implements QrCodeDecoder.ResultCallback, QrCodeView.FullscreenListener {
|
||||||
|
|
||||||
|
static final String TAG = org.briarproject.briar.android.keyagreement.KeyAgreementFragment.class.getName();
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger(TAG);
|
||||||
|
@SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19
|
||||||
|
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Provider<KeyAgreementTask> keyAgreementTaskProvider;
|
||||||
|
@Inject
|
||||||
|
PayloadEncoder payloadEncoder;
|
||||||
|
@Inject
|
||||||
|
PayloadParser payloadParser;
|
||||||
|
@Inject
|
||||||
|
@IoExecutor
|
||||||
|
Executor ioExecutor;
|
||||||
|
@Inject
|
||||||
|
EventBus eventBus;
|
||||||
|
|
||||||
|
private CameraView cameraView;
|
||||||
|
private LinearLayout cameraOverlay;
|
||||||
|
private View statusView;
|
||||||
|
private QrCodeView qrCodeView;
|
||||||
|
private TextView status;
|
||||||
|
|
||||||
|
private boolean gotRemotePayload;
|
||||||
|
private volatile boolean gotLocalPayload;
|
||||||
|
private KeyAgreementTask task;
|
||||||
|
private ShardQrCodeEventListener
|
||||||
|
listener;
|
||||||
|
|
||||||
|
public static ShardQrCodeFragment newInstance() {
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
ShardQrCodeFragment
|
||||||
|
fragment = new ShardQrCodeFragment();
|
||||||
|
fragment.setArguments(args);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
listener = (ShardQrCodeEventListener) context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void injectFragment(ActivityComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUniqueTag() {
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
qrCodeView = view.findViewById(R.id.qr_code_view);
|
||||||
|
qrCodeView.setFullscreenListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
requireActivity().setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR);
|
||||||
|
cameraView.setPreviewConsumer(new QrCodeDecoder(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
try {
|
||||||
|
cameraView.start();
|
||||||
|
} catch (CameraException e) {
|
||||||
|
logCameraExceptionAndFinish(e);
|
||||||
|
}
|
||||||
|
startListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
stopListening();
|
||||||
|
try {
|
||||||
|
cameraView.stop();
|
||||||
|
} catch (CameraException e) {
|
||||||
|
logCameraExceptionAndFinish(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private void logCameraExceptionAndFinish(CameraException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
Toast.makeText(getActivity(), R.string.camera_error,
|
||||||
|
LENGTH_LONG).show();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private void reset() {
|
||||||
|
// If we've stopped the camera view, restart it
|
||||||
|
if (gotRemotePayload) {
|
||||||
|
try {
|
||||||
|
cameraView.start();
|
||||||
|
} catch (CameraException e) {
|
||||||
|
logCameraExceptionAndFinish(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusView.setVisibility(INVISIBLE);
|
||||||
|
cameraView.setVisibility(VISIBLE);
|
||||||
|
gotRemotePayload = false;
|
||||||
|
gotLocalPayload = false;
|
||||||
|
startListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private void qrCodeScanned(String content) {
|
||||||
|
try {
|
||||||
|
byte[] payloadBytes = content.getBytes(ISO_8859_1);
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Remote payload is " + payloadBytes.length + " bytes");
|
||||||
|
Payload remotePayload = payloadParser.parse(payloadBytes);
|
||||||
|
gotRemotePayload = true;
|
||||||
|
cameraView.stop();
|
||||||
|
cameraView.setVisibility(INVISIBLE);
|
||||||
|
statusView.setVisibility(VISIBLE);
|
||||||
|
status.setText(R.string.connecting_to_device);
|
||||||
|
task.connectAndRunProtocol(remotePayload);
|
||||||
|
} catch (UnsupportedVersionException e) {
|
||||||
|
reset();
|
||||||
|
String msg;
|
||||||
|
if (e.isTooOld()) {
|
||||||
|
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(ContactExchangeErrorFragment.newInstance(msg));
|
||||||
|
} catch (CameraException e) {
|
||||||
|
logCameraExceptionAndFinish(e);
|
||||||
|
} catch (IOException | IllegalArgumentException e) {
|
||||||
|
LOG.log(WARNING, "QR Code Invalid", e);
|
||||||
|
reset();
|
||||||
|
Toast.makeText(getActivity(), R.string.qr_code_invalid,
|
||||||
|
LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void eventOccurred(Event e) {
|
||||||
|
if (e instanceof KeyAgreementListeningEvent) {
|
||||||
|
KeyAgreementListeningEvent event = (KeyAgreementListeningEvent) e;
|
||||||
|
gotLocalPayload = true;
|
||||||
|
setQrCode(event.getLocalPayload());
|
||||||
|
} else if (e instanceof KeyAgreementFailedEvent) {
|
||||||
|
keyAgreementFailed();
|
||||||
|
} else if (e instanceof KeyAgreementWaitingEvent) {
|
||||||
|
keyAgreementWaiting();
|
||||||
|
} else if (e instanceof KeyAgreementStartedEvent) {
|
||||||
|
keyAgreementStarted();
|
||||||
|
} else if (e instanceof KeyAgreementAbortedEvent) {
|
||||||
|
KeyAgreementAbortedEvent event = (KeyAgreementAbortedEvent) e;
|
||||||
|
keyAgreementAborted(event.didRemoteAbort());
|
||||||
|
} else if (e instanceof KeyAgreementFinishedEvent) {
|
||||||
|
keyAgreementFinished(((KeyAgreementFinishedEvent) e).getResult());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private void keyAgreementFailed() {
|
||||||
|
reset();
|
||||||
|
listener.keyAgreementFailed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private void keyAgreementWaiting() {
|
||||||
|
status.setText(listener.keyAgreementWaiting());
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private void keyAgreementStarted() {
|
||||||
|
qrCodeView.setVisibility(INVISIBLE);
|
||||||
|
statusView.setVisibility(VISIBLE);
|
||||||
|
status.setText(listener.keyAgreementStarted());
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private void keyAgreementAborted(boolean remoteAborted) {
|
||||||
|
reset();
|
||||||
|
listener.keyAgreementAborted(remoteAborted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
private void keyAgreementFinished(KeyAgreementResult result) {
|
||||||
|
statusView.setVisibility(VISIBLE);
|
||||||
|
status.setText(listener.keyAgreementFinished(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setQrCode(Payload localPayload) {
|
||||||
|
Context context = getContext();
|
||||||
|
if (context == null) return;
|
||||||
|
DisplayMetrics dm = context.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);
|
||||||
|
runOnUiThreadUnlessDestroyed(() -> qrCodeView.setQrCode(qrCode));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleResult(Result result) {
|
||||||
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
|
LOG.info("Got result from decoder");
|
||||||
|
// Ignore results until the KeyAgreementTask is ready
|
||||||
|
if (!gotLocalPayload) return;
|
||||||
|
if (!gotRemotePayload) qrCodeScanned(result.getText());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finish() {
|
||||||
|
getActivity().getSupportFragmentManager().popBackStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
interface ShardQrCodeEventListener {
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
void keyAgreementFailed();
|
||||||
|
|
||||||
|
// Should return a string to be displayed as status.
|
||||||
|
@UiThread
|
||||||
|
@Nullable
|
||||||
|
String keyAgreementWaiting();
|
||||||
|
|
||||||
|
// Should return a string to be displayed as status.
|
||||||
|
@UiThread
|
||||||
|
@Nullable
|
||||||
|
String keyAgreementStarted();
|
||||||
|
|
||||||
|
// Will show an error fragment.
|
||||||
|
@UiThread
|
||||||
|
void keyAgreementAborted(boolean remoteAborted);
|
||||||
|
|
||||||
|
// Should return a string to be displayed as status.
|
||||||
|
@UiThread
|
||||||
|
@Nullable
|
||||||
|
String keyAgreementFinished(KeyAgreementResult result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,48 +13,58 @@ import org.briarproject.briar.android.fragment.BaseFragment;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
public class ShardsSentFragment extends BaseFragment {
|
public class ShardsSentFragment extends BaseFragment {
|
||||||
|
|
||||||
public static final String TAG = ShardsSentFragment.class.getName();
|
public static final String TAG = ShardsSentFragment.class.getName();
|
||||||
|
|
||||||
protected ShardsSentDismissedListener listener;
|
interface ShardsSentDismissedListener {
|
||||||
|
|
||||||
@Override
|
@UiThread
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
void shardsSentDismissed();
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
requireActivity().setTitle(R.string.title_distributed_backup);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
}
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
|
||||||
View view = inflater.inflate(R.layout.fragment_shards_sent,
|
|
||||||
container, false);
|
|
||||||
|
|
||||||
Button button = view.findViewById(R.id.button);
|
protected ShardsSentDismissedListener listener;
|
||||||
button.setOnClickListener(e -> {
|
|
||||||
listener.shardsSentDismissed();
|
|
||||||
});
|
|
||||||
|
|
||||||
return view;
|
@Override
|
||||||
}
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
requireActivity().setTitle(R.string.title_distributed_backup);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Nullable
|
||||||
public void onAttach(Context context) {
|
@Override
|
||||||
super.onAttach(context);
|
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||||
listener = (ShardsSentDismissedListener) context;
|
@Nullable ViewGroup container,
|
||||||
}
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_shards_sent,
|
||||||
|
container, false);
|
||||||
|
|
||||||
|
Button button = view.findViewById(R.id.button);
|
||||||
|
button.setOnClickListener(e -> {
|
||||||
|
listener.shardsSentDismissed();
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
listener = (ShardsSentDismissedListener) context;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUniqueTag() {
|
public String getUniqueTag() {
|
||||||
return TAG;
|
return TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectFragment(ActivityComponent component) {
|
public void injectFragment(ActivityComponent component) {
|
||||||
component.inject(this);
|
component.inject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,162 +8,175 @@ import android.view.MenuInflater;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.contactselection.ContactSelectorListener;
|
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
import org.magmacollective.darkcrystal.secretsharingwrapper.SecretSharingWrapper;
|
import org.magmacollective.darkcrystal.secretsharingwrapper.SecretSharingWrapper;
|
||||||
|
|
||||||
import static java.util.Objects.requireNonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
public class ThresholdSelectorFragment extends BaseFragment {
|
public class ThresholdSelectorFragment extends BaseFragment {
|
||||||
|
|
||||||
public static final String TAG = ThresholdSelectorFragment.class.getName();
|
public static final String TAG = ThresholdSelectorFragment.class.getName();
|
||||||
private static final String NUMBER_CUSTODIANS = "numberCustodians";
|
private static final String NUMBER_CUSTODIANS = "numberCustodians";
|
||||||
|
|
||||||
protected ThresholdDefinedListener listener;
|
protected ThresholdDefinedListener listener;
|
||||||
|
|
||||||
// TODO this should be the actual number of custodians
|
private int numberOfCustodians;
|
||||||
private int numberOfCustodians;
|
private int threshold;
|
||||||
private int threshold;
|
private int recommendedThreshold;
|
||||||
private int recommendedThreshold;
|
private SeekBar seekBar;
|
||||||
private SeekBar seekBar;
|
private TextView thresholdRepresentation;
|
||||||
private TextView thresholdRepresentation;
|
private TextView message;
|
||||||
private TextView message;
|
private TextView mOfn;
|
||||||
private TextView mOfn;
|
|
||||||
|
|
||||||
public static ThresholdSelectorFragment newInstance(int numberCustodians) {
|
public static ThresholdSelectorFragment newInstance(int numberCustodians) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putInt(NUMBER_CUSTODIANS, numberCustodians);
|
bundle.putInt(NUMBER_CUSTODIANS, numberCustodians);
|
||||||
ThresholdSelectorFragment fragment = new ThresholdSelectorFragment();
|
ThresholdSelectorFragment fragment = new ThresholdSelectorFragment();
|
||||||
fragment.setArguments(bundle);
|
fragment.setArguments(bundle);
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
requireActivity().setTitle(R.string.title_define_threshold);
|
requireActivity().setTitle(R.string.title_define_threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||||
View view = inflater.inflate(R.layout.fragment_select_threshold,
|
@Nullable ViewGroup container,
|
||||||
container, false);
|
@Nullable Bundle savedInstanceState) {
|
||||||
Bundle args = requireArguments();
|
View view = inflater.inflate(R.layout.fragment_select_threshold,
|
||||||
numberOfCustodians = args.getInt(NUMBER_CUSTODIANS);
|
container, false);
|
||||||
|
Bundle args = requireArguments();
|
||||||
|
numberOfCustodians = args.getInt(NUMBER_CUSTODIANS);
|
||||||
|
seekBar = view.findViewById(R.id.seekBar);
|
||||||
|
thresholdRepresentation =
|
||||||
|
view.findViewById(R.id.textViewThresholdRepresentation);
|
||||||
|
message = view.findViewById(R.id.textViewMessage);
|
||||||
|
mOfn = view.findViewById(R.id.textViewmOfn);
|
||||||
|
|
||||||
seekBar = view.findViewById(R.id.seekBar);
|
if (numberOfCustodians == 2) {
|
||||||
thresholdRepresentation = view.findViewById(R.id.textViewThresholdRepresentation);
|
message.setText(R.string.threshold_too_few_custodians);
|
||||||
message = view.findViewById(R.id.textViewMessage);
|
}
|
||||||
mOfn = view.findViewById(R.id.textViewmOfn);
|
if (numberOfCustodians > 3) {
|
||||||
int max = numberOfCustodians - 3;
|
seekBar.setMax(numberOfCustodians -3);
|
||||||
seekBar.setMax(max);
|
seekBar.setProgress(threshold - 2);
|
||||||
seekBar.setOnSeekBarChangeListener(new SeekBarListener());
|
seekBar.setOnSeekBarChangeListener(new SeekBarListener());
|
||||||
recommendedThreshold = SecretSharingWrapper.defaultThreshold(numberOfCustodians);
|
recommendedThreshold =
|
||||||
threshold = recommendedThreshold;
|
SecretSharingWrapper.defaultThreshold(numberOfCustodians);
|
||||||
seekBar.setProgress(threshold - 2);
|
threshold = recommendedThreshold;
|
||||||
|
|
||||||
thresholdRepresentation.setText(buildThresholdRepresentationString());
|
} else {
|
||||||
setmOfnText();
|
seekBar.setEnabled(false);
|
||||||
return view;
|
threshold = 2;
|
||||||
|
seekBar.setMax(numberOfCustodians);
|
||||||
|
seekBar.setProgress(threshold);
|
||||||
|
TextView t = view.findViewById(R.id.title_threshold);
|
||||||
|
t.setText(R.string.threshold_disabled);
|
||||||
|
}
|
||||||
|
thresholdRepresentation.setText(buildThresholdRepresentationString());
|
||||||
|
setmOfnText();
|
||||||
|
return view;
|
||||||
// return super.onCreateView(inflater, container, savedInstanceState);
|
// return super.onCreateView(inflater, container, savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setmOfnText() {
|
private void setmOfnText() {
|
||||||
mOfn.setText(String.format("%d of %d contacts needed to recover your account", threshold, numberOfCustodians));
|
mOfn.setText(String.format(
|
||||||
}
|
getString(R.string.threshold_m_of_n), threshold,
|
||||||
|
numberOfCustodians));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onAttach(Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
listener = (ThresholdDefinedListener) context;
|
listener = (ThresholdDefinedListener) context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUniqueTag() {
|
public String getUniqueTag() {
|
||||||
return TAG;
|
return TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectFragment(ActivityComponent component) {
|
public void injectFragment(ActivityComponent component) {
|
||||||
component.inject(this);
|
component.inject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
inflater.inflate(R.menu.define_threshold_actions, menu);
|
inflater.inflate(R.menu.define_threshold_actions, menu);
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.action_threshold_defined:
|
case R.id.action_threshold_defined:
|
||||||
try {
|
try {
|
||||||
listener.thresholdDefined(threshold);
|
listener.thresholdDefined(threshold);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildThresholdRepresentationString () {
|
private String buildThresholdRepresentationString() {
|
||||||
String thresholdRepresentationText = "";
|
String thresholdRepresentationText = "";
|
||||||
for (int i = 0; i < threshold; i++) {
|
for (int i = 0; i < threshold; i++) {
|
||||||
thresholdRepresentationText += getString(R.string.filled_bullet);
|
thresholdRepresentationText += getString(R.string.filled_bullet);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < (numberOfCustodians - threshold); i++) {
|
for (int i = 0; i < (numberOfCustodians - threshold); i++) {
|
||||||
thresholdRepresentationText += getString(R.string.linear_bullet);
|
thresholdRepresentationText += getString(R.string.linear_bullet);
|
||||||
}
|
}
|
||||||
return thresholdRepresentationText;
|
return thresholdRepresentationText;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SeekBarListener implements SeekBar.OnSeekBarChangeListener {
|
private class SeekBarListener implements SeekBar.OnSeekBarChangeListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(SeekBar seekBar, int progress,
|
public void onProgressChanged(SeekBar seekBar, int progress,
|
||||||
boolean fromUser) {
|
boolean fromUser) {
|
||||||
threshold = progress + 2;
|
threshold = progress + 2;
|
||||||
|
|
||||||
thresholdRepresentation.setText(
|
thresholdRepresentation.setText(
|
||||||
buildThresholdRepresentationString()
|
buildThresholdRepresentationString()
|
||||||
);
|
);
|
||||||
setmOfnText();
|
setmOfnText();
|
||||||
|
|
||||||
int sanityLevel = SecretSharingWrapper.thresholdSanity(threshold, numberOfCustodians);
|
int sanityLevel = SecretSharingWrapper
|
||||||
int text = R.string.threshold_secure;
|
.thresholdSanity(threshold, numberOfCustodians);
|
||||||
if (threshold == recommendedThreshold) text = R.string.threshold_recommended;
|
int text = R.string.threshold_secure;
|
||||||
if (sanityLevel < -1) text = R.string.threshold_low_insecure;
|
if (threshold == recommendedThreshold)
|
||||||
if (sanityLevel > 0) text = R.string.threshold_high_insecure;
|
text = R.string.threshold_recommended;
|
||||||
message.setText(text);
|
if (sanityLevel < -1) text = R.string.threshold_low_insecure;
|
||||||
// TODO change colour of thresholdRepresentation to green/red based on sanityLevel
|
if (sanityLevel > 0) text = R.string.threshold_high_insecure;
|
||||||
}
|
message.setText(text);
|
||||||
|
// TODO change colour of thresholdRepresentation to green/red based on sanityLevel
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.briarproject.briar.socialbackup;
|
||||||
|
|
||||||
|
import org.briarproject.briar.android.socialbackup.DarkCrystalImpl;
|
||||||
|
import org.briarproject.briar.api.socialbackup.DarkCrystal;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class AndroidDarkCrystalModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
DarkCrystal darkCrystal(DarkCrystalImpl darkCrystal) {
|
||||||
|
return darkCrystal;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
briar-android/src/main/res/layout/activity_recover.xml
Normal file
8
briar-android/src/main/res/layout/activity_recover.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/fragmentContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
app:srcCompat="@drawable/qr_code_intro" />
|
app:srcCompat="@drawable/qr_code_intro" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/button"
|
android:id="@+id/beginButton"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||||
|
|
||||||
<string name="app_name" translatable="false">Briar</string>
|
<string name="app_name" translatable="false">Briar SB</string>
|
||||||
<string name="app_package" translatable="false">org.briarproject.briar.android</string>
|
<string name="app_package" translatable="false">org.briarproject.briar.socialbackup</string>
|
||||||
|
|
||||||
<!-- Setup -->
|
<!-- Setup -->
|
||||||
<string name="setup_title">Welcome to Briar</string>
|
<string name="setup_title">Welcome to Briar</string>
|
||||||
@@ -655,12 +655,15 @@
|
|||||||
<string name="select_at_least_n_contacts">Please select at least %d contacts</string>
|
<string name="select_at_least_n_contacts">Please select at least %d contacts</string>
|
||||||
<string name="select_at_least_n_more_contacts">Please select at least %d more contacts</string>
|
<string name="select_at_least_n_more_contacts">Please select at least %d more contacts</string>
|
||||||
|
|
||||||
<string name="threshold">The minimum number of trusted contacts needed to restore your account:</string>
|
<string name="threshold">Choose the minimum number of trusted contacts needed to restore your account</string>
|
||||||
|
<string name="threshold_disabled">Two trusted contacts will be needed to restore your account</string>
|
||||||
<string name="threshold_secure">Secure</string>
|
<string name="threshold_secure">Secure</string>
|
||||||
<string name="threshold_recommended">Secure - recommended threshold</string>
|
<string name="threshold_recommended">Secure - recommended threshold</string>
|
||||||
<string name="threshold_low_insecure">Insecure – higher threshold recommended</string>
|
<string name="threshold_low_insecure">Insecure – higher threshold recommended</string>
|
||||||
<string name="threshold_high_insecure">Danger of loss – lower threshold recommended</string>
|
<string name="threshold_high_insecure">Danger of loss – lower threshold recommended</string>
|
||||||
|
<string name="threshold_too_few_custodians">Danger of loss - more contacts recommended</string>
|
||||||
<string name="threshold_defined">Choose Threshold</string>
|
<string name="threshold_defined">Choose Threshold</string>
|
||||||
|
<string name="threshold_m_of_n">%d of %d contacts needed to recover your account</string>
|
||||||
|
|
||||||
<string name="backup_done_info">Backup pieces sent to trusted contacts</string>
|
<string name="backup_done_info">Backup pieces sent to trusted contacts</string>
|
||||||
<string name="backup_done_dismiss">Got it</string>
|
<string name="backup_done_dismiss">Got it</string>
|
||||||
@@ -691,7 +694,7 @@
|
|||||||
|
|
||||||
<string name="title_distributed_backup">Social Backup</string>
|
<string name="title_distributed_backup">Social Backup</string>
|
||||||
<string name="title_select_custodians">Select Trusted Contacts</string>
|
<string name="title_select_custodians">Select Trusted Contacts</string>
|
||||||
<string name="title_define_threshold">Choose Threshold</string>
|
<string name="title_define_threshold">Threshold</string>
|
||||||
<string name="title_recovery_mode">Recovery Mode</string>
|
<string name="title_recovery_mode">Recovery Mode</string>
|
||||||
<string name="title_help_recover">Help recover account</string>
|
<string name="title_help_recover">Help recover account</string>
|
||||||
|
|
||||||
@@ -706,11 +709,17 @@
|
|||||||
|
|
||||||
<!-- Symbols for visualising threshold values for social backup -->
|
<!-- Symbols for visualising threshold values for social backup -->
|
||||||
<string name="filled_bullet">\u25CF</string>
|
<string name="filled_bullet">\u25CF</string>
|
||||||
<string name="linear_bullet">\u25CB</string>
|
<string name="linear_bullet">\u25CB</string>
|
||||||
|
|
||||||
<!-- activity names -->
|
<!-- activity names -->
|
||||||
<string name="activity_name_distributed_backup">Social Backup</string>
|
<string name="activity_name_distributed_backup">Social Backup</string>
|
||||||
<string name="activity_name_old_distributed_backup">Old Social Backup</string>
|
<string name="activity_name_old_distributed_backup">Old Social Backup</string>
|
||||||
|
|
||||||
|
<!-- conversation -->
|
||||||
|
<string name="social_backup_shard_received">You have received a social backup shard.</string>
|
||||||
|
<string name="social_backup_shard_sent">You have sent a social backup shard.</string>
|
||||||
|
|
||||||
<string name="activity_name_new_or_recover_account">Create new account or recover existing account</string>
|
<string name="activity_name_new_or_recover_account">Create new account or recover existing account</string>
|
||||||
|
<string name="activity_name_recovery">Recover Account</string>
|
||||||
|
<string name="activity_name_custodian_help_recovery">Help recover account</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.briarproject.briar.api.introduction.IntroductionResponse;
|
|||||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
|
||||||
|
import org.briarproject.briar.api.socialbackup.ShardMessageHeader;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface ConversationMessageVisitor<T> {
|
public interface ConversationMessageVisitor<T> {
|
||||||
@@ -31,4 +32,6 @@ public interface ConversationMessageVisitor<T> {
|
|||||||
T visitIntroductionRequest(IntroductionRequest r);
|
T visitIntroductionRequest(IntroductionRequest r);
|
||||||
|
|
||||||
T visitIntroductionResponse(IntroductionResponse r);
|
T visitIntroductionResponse(IntroductionResponse r);
|
||||||
|
|
||||||
|
T visitShardMessage(ShardMessageHeader r);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package org.briarproject.briar.api.keyagreement;
|
||||||
|
|
||||||
|
public class KeyAgreementUtils {
|
||||||
|
|
||||||
|
public enum BluetoothDecision {
|
||||||
|
/**
|
||||||
|
* We haven't asked the user about Bluetooth discoverability.
|
||||||
|
*/
|
||||||
|
UNKNOWN,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The device doesn't have a Bluetooth adapter.
|
||||||
|
*/
|
||||||
|
NO_ADAPTER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We're waiting for the user to accept or refuse discoverability.
|
||||||
|
*/
|
||||||
|
WAITING,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user has accepted discoverability.
|
||||||
|
*/
|
||||||
|
ACCEPTED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user has refused discoverability.
|
||||||
|
*/
|
||||||
|
REFUSED
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Permission {
|
||||||
|
UNKNOWN, GRANTED, SHOW_RATIONALE, PERMANENTLY_DENIED
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package org.briarproject.briar.api.socialbackup;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
|
import org.briarproject.briar.api.attachment.AttachmentHeader;
|
||||||
|
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
|
||||||
|
import org.briarproject.briar.api.conversation.ConversationMessageVisitor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class ShardMessageHeader extends ConversationMessageHeader {
|
||||||
|
|
||||||
|
private final List<AttachmentHeader> attachmentHeaders;
|
||||||
|
|
||||||
|
public ShardMessageHeader(MessageId id, GroupId groupId, long timestamp,
|
||||||
|
boolean local, boolean read, boolean sent, boolean seen,
|
||||||
|
List<AttachmentHeader> headers) {
|
||||||
|
super(id, groupId, timestamp, local, read, sent, seen);
|
||||||
|
this.attachmentHeaders = headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AttachmentHeader> getAttachmentHeaders() {
|
||||||
|
return attachmentHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(ConversationMessageVisitor<T> v) {
|
||||||
|
return v.visitShardMessage(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.briarproject.briar.api.socialbackup;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.briar.api.conversation.event.ConversationMessageReceivedEvent;
|
||||||
|
|
||||||
|
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class ShardReceivedEvent
|
||||||
|
extends ConversationMessageReceivedEvent<ShardMessageHeader> {
|
||||||
|
|
||||||
|
public ShardReceivedEvent(ShardMessageHeader shardMessageHeader,
|
||||||
|
ContactId contactId) {
|
||||||
|
super(shardMessageHeader, contactId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,17 +1,22 @@
|
|||||||
package org.briarproject.briar.api.socialbackup;
|
package org.briarproject.briar.api.socialbackup;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.ClientId;
|
import org.briarproject.bramble.api.sync.ClientId;
|
||||||
|
import org.briarproject.briar.api.conversation.ConversationManager;
|
||||||
|
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface SocialBackupManager {
|
public interface SocialBackupManager extends
|
||||||
|
ConversationManager.ConversationClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The unique ID of the social backup client.
|
* The unique ID of the social backup client.
|
||||||
@@ -44,4 +49,10 @@ public interface SocialBackupManager {
|
|||||||
*/
|
*/
|
||||||
void createBackup(Transaction txn, List<ContactId> custodianIds,
|
void createBackup(Transaction txn, List<ContactId> custodianIds,
|
||||||
int threshold) throws DbException;
|
int threshold) throws DbException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Collection<ConversationMessageHeader> getMessageHeaders(
|
||||||
|
Transaction txn, ContactId contactId) throws DbException;
|
||||||
|
|
||||||
|
boolean amCustodian(Transaction txn, ContactId contactId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import org.briarproject.briar.privategroup.PrivateGroupModule;
|
|||||||
import org.briarproject.briar.privategroup.invitation.GroupInvitationModule;
|
import org.briarproject.briar.privategroup.invitation.GroupInvitationModule;
|
||||||
import org.briarproject.briar.sharing.SharingModule;
|
import org.briarproject.briar.sharing.SharingModule;
|
||||||
import org.briarproject.briar.socialbackup.SocialBackupModule;
|
import org.briarproject.briar.socialbackup.SocialBackupModule;
|
||||||
|
//import org.briarproject.briar.socialbackup.DefaultSocialBackupModule;
|
||||||
|
|
||||||
public interface BriarCoreEagerSingletons {
|
public interface BriarCoreEagerSingletons {
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.briarproject.briar.socialbackup;
|
||||||
|
|
||||||
|
import org.briarproject.briar.api.socialbackup.DarkCrystal;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class DefaultDarkCrystalModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
DarkCrystal darkCrystal(DarkCrystalStub darkCrystal) {
|
||||||
|
return darkCrystal;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ public interface SocialBackupConstants {
|
|||||||
String GROUP_KEY_VERSION = "version";
|
String GROUP_KEY_VERSION = "version";
|
||||||
|
|
||||||
// Message metadata keys
|
// Message metadata keys
|
||||||
|
String MSG_KEY_TIMESTAMP = "timestamp";
|
||||||
String MSG_KEY_MESSAGE_TYPE = "messageType";
|
String MSG_KEY_MESSAGE_TYPE = "messageType";
|
||||||
String MSG_KEY_LOCAL = "local";
|
String MSG_KEY_LOCAL = "local";
|
||||||
String MSG_KEY_VERSION = "version";
|
String MSG_KEY_VERSION = "version";
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.briar.socialbackup;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.Pair;
|
import org.briarproject.bramble.api.Pair;
|
||||||
import org.briarproject.bramble.api.client.BdfIncomingMessageHook;
|
|
||||||
import org.briarproject.bramble.api.client.ClientHelper;
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
import org.briarproject.bramble.api.client.ContactGroupFactory;
|
import org.briarproject.bramble.api.client.ContactGroupFactory;
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
@@ -34,14 +33,23 @@ import org.briarproject.bramble.api.sync.Group.Visibility;
|
|||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
||||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook;
|
import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook;
|
||||||
|
import org.briarproject.briar.api.attachment.AttachmentHeader;
|
||||||
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
|
import org.briarproject.briar.api.conversation.ConversationManager;
|
||||||
|
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
|
||||||
|
import org.briarproject.briar.api.conversation.DeletionResult;
|
||||||
import org.briarproject.briar.api.socialbackup.BackupExistsException;
|
import org.briarproject.briar.api.socialbackup.BackupExistsException;
|
||||||
import org.briarproject.briar.api.socialbackup.BackupMetadata;
|
import org.briarproject.briar.api.socialbackup.BackupMetadata;
|
||||||
import org.briarproject.briar.api.socialbackup.DarkCrystal;
|
import org.briarproject.briar.api.socialbackup.DarkCrystal;
|
||||||
import org.briarproject.briar.api.socialbackup.Shard;
|
import org.briarproject.briar.api.socialbackup.Shard;
|
||||||
|
import org.briarproject.briar.api.socialbackup.ShardMessageHeader;
|
||||||
|
import org.briarproject.briar.api.socialbackup.ShardReceivedEvent;
|
||||||
import org.briarproject.briar.api.socialbackup.SocialBackupManager;
|
import org.briarproject.briar.api.socialbackup.SocialBackupManager;
|
||||||
|
import org.briarproject.briar.client.ConversationClientImpl;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -49,22 +57,25 @@ import java.util.List;
|
|||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.Collections.singletonMap;
|
import static java.util.Collections.singletonMap;
|
||||||
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
||||||
|
import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
|
||||||
import static org.briarproject.briar.socialbackup.MessageType.BACKUP;
|
import static org.briarproject.briar.socialbackup.MessageType.BACKUP;
|
||||||
import static org.briarproject.briar.socialbackup.MessageType.SHARD;
|
import static org.briarproject.briar.socialbackup.MessageType.SHARD;
|
||||||
import static org.briarproject.briar.socialbackup.SocialBackupConstants.GROUP_KEY_CONTACT_ID;
|
import static org.briarproject.briar.socialbackup.SocialBackupConstants.GROUP_KEY_CONTACT_ID;
|
||||||
import static org.briarproject.briar.socialbackup.SocialBackupConstants.GROUP_KEY_VERSION;
|
import static org.briarproject.briar.socialbackup.SocialBackupConstants.GROUP_KEY_VERSION;
|
||||||
import static org.briarproject.briar.socialbackup.SocialBackupConstants.MSG_KEY_LOCAL;
|
import static org.briarproject.briar.socialbackup.SocialBackupConstants.MSG_KEY_LOCAL;
|
||||||
import static org.briarproject.briar.socialbackup.SocialBackupConstants.MSG_KEY_MESSAGE_TYPE;
|
import static org.briarproject.briar.socialbackup.SocialBackupConstants.MSG_KEY_MESSAGE_TYPE;
|
||||||
|
import static org.briarproject.briar.socialbackup.SocialBackupConstants.MSG_KEY_TIMESTAMP;
|
||||||
import static org.briarproject.briar.socialbackup.SocialBackupConstants.MSG_KEY_VERSION;
|
import static org.briarproject.briar.socialbackup.SocialBackupConstants.MSG_KEY_VERSION;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class SocialBackupManagerImpl extends BdfIncomingMessageHook
|
class SocialBackupManagerImpl extends ConversationClientImpl
|
||||||
implements SocialBackupManager, OpenDatabaseHook, ContactHook,
|
implements SocialBackupManager, OpenDatabaseHook, ContactHook,
|
||||||
ClientVersioningHook {
|
ClientVersioningHook {
|
||||||
|
|
||||||
@@ -100,8 +111,11 @@ class SocialBackupManagerImpl extends BdfIncomingMessageHook
|
|||||||
ContactManager contactManager,
|
ContactManager contactManager,
|
||||||
CryptoComponent crypto,
|
CryptoComponent crypto,
|
||||||
DarkCrystal darkCrystal,
|
DarkCrystal darkCrystal,
|
||||||
Clock clock) {
|
Clock clock,
|
||||||
super(db, clientHelper, metadataParser);
|
MessageTracker messageTracker,
|
||||||
|
ConversationManager conversationManager
|
||||||
|
) {
|
||||||
|
super(db, clientHelper, metadataParser, messageTracker);
|
||||||
this.clientVersioningManager = clientVersioningManager;
|
this.clientVersioningManager = clientVersioningManager;
|
||||||
this.transportPropertyManager = transportPropertyManager;
|
this.transportPropertyManager = transportPropertyManager;
|
||||||
this.contactGroupFactory = contactGroupFactory;
|
this.contactGroupFactory = contactGroupFactory;
|
||||||
@@ -165,20 +179,21 @@ class SocialBackupManagerImpl extends BdfIncomingMessageHook
|
|||||||
protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
|
protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
|
||||||
BdfDictionary meta) throws DbException, FormatException {
|
BdfDictionary meta) throws DbException, FormatException {
|
||||||
MessageType type = MessageType.fromValue(body.getLong(0).intValue());
|
MessageType type = MessageType.fromValue(body.getLong(0).intValue());
|
||||||
|
System.out.println("GOT INCOMING DC MESSAGE");
|
||||||
if (type == SHARD) {
|
if (type == SHARD) {
|
||||||
// Only one shard should be received from each contact
|
// Only one shard should be received from each contact
|
||||||
if (findMessage(txn, m.getGroupId(), SHARD, false) != null) {
|
if (findMessage(txn, m.getGroupId(), SHARD, false) != null) {
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
ContactId contactId = getContactId(txn, m.getGroupId());
|
||||||
// Add the shard to our backup, if any
|
// Add the shard to our backup, if any
|
||||||
if (localBackupExists(txn)) {
|
if (localBackupExists(txn)) {
|
||||||
Shard shard = messageParser.parseShardMessage(body);
|
Shard shard = messageParser.parseShardMessage(body);
|
||||||
ContactId c = getContactId(txn, m.getGroupId());
|
|
||||||
List<ContactData> contactData = loadContactData(txn);
|
List<ContactData> contactData = loadContactData(txn);
|
||||||
ListIterator<ContactData> it = contactData.listIterator();
|
ListIterator<ContactData> it = contactData.listIterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
ContactData cd = it.next();
|
ContactData cd = it.next();
|
||||||
if (cd.getContact().getId().equals(c)) {
|
if (cd.getContact().getId().equals(contactId)) {
|
||||||
it.set(new ContactData(cd.getContact(),
|
it.set(new ContactData(cd.getContact(),
|
||||||
cd.getProperties(), shard));
|
cd.getProperties(), shard));
|
||||||
updateBackup(txn, contactData);
|
updateBackup(txn, contactData);
|
||||||
@@ -186,6 +201,12 @@ class SocialBackupManagerImpl extends BdfIncomingMessageHook
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
messageTracker.trackIncomingMessage(txn, m);
|
||||||
|
|
||||||
|
MessageStatus status = db.getMessageStatus(txn, contactId,
|
||||||
|
m.getId());
|
||||||
|
txn.attach(new ShardReceivedEvent(
|
||||||
|
createShardMessageHeader(m, meta, status), contactId));
|
||||||
} else if (type == BACKUP) {
|
} else if (type == BACKUP) {
|
||||||
// Keep the newest version of the backup, delete any older versions
|
// Keep the newest version of the backup, delete any older versions
|
||||||
int version = meta.getLong(MSG_KEY_VERSION).intValue();
|
int version = meta.getLong(MSG_KEY_VERSION).intValue();
|
||||||
@@ -209,6 +230,17 @@ class SocialBackupManagerImpl extends BdfIncomingMessageHook
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean amCustodian(Transaction txn, ContactId contactId) {
|
||||||
|
try {
|
||||||
|
GroupId groupId = getContactGroup(db.getContact(txn, contactId)).getId();
|
||||||
|
return findMessage(txn, groupId, SHARD, false) != null;
|
||||||
|
} catch (DbException e) {
|
||||||
|
return false;
|
||||||
|
} catch (FormatException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BackupMetadata getBackupMetadata(Transaction txn)
|
public BackupMetadata getBackupMetadata(Transaction txn)
|
||||||
@@ -256,17 +288,97 @@ class SocialBackupManagerImpl extends BdfIncomingMessageHook
|
|||||||
new BackupMetadata(secret, authors, threshold, 0);
|
new BackupMetadata(secret, authors, threshold, 0);
|
||||||
BdfDictionary meta =
|
BdfDictionary meta =
|
||||||
backupMetadataEncoder.encodeBackupMetadata(backupMetadata);
|
backupMetadataEncoder.encodeBackupMetadata(backupMetadata);
|
||||||
|
|
||||||
|
if (!db.containsGroup(txn, localGroup.getId()))
|
||||||
|
db.addGroup(txn, localGroup);
|
||||||
clientHelper.mergeGroupMetadata(txn, localGroup.getId(), meta);
|
clientHelper.mergeGroupMetadata(txn, localGroup.getId(), meta);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Group getContactGroup(Contact c) {
|
@Override
|
||||||
|
public Group getContactGroup(Contact c) {
|
||||||
return contactGroupFactory.createContactGroup(CLIENT_ID,
|
return contactGroupFactory.createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, c);
|
MAJOR_VERSION, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ShardMessageHeader createShardMessageHeader(
|
||||||
|
Message message, BdfDictionary meta, MessageStatus status
|
||||||
|
)
|
||||||
|
throws FormatException {
|
||||||
|
|
||||||
|
boolean isLocal = meta.getBoolean(MSG_KEY_LOCAL);
|
||||||
|
boolean read = meta.getBoolean(MSG_KEY_READ, false);
|
||||||
|
long timestamp;
|
||||||
|
if (isLocal) {
|
||||||
|
timestamp = meta.getLong(MSG_KEY_TIMESTAMP);
|
||||||
|
} else {
|
||||||
|
timestamp = message.getTimestamp();
|
||||||
|
}
|
||||||
|
List<AttachmentHeader> attachmentHeaders =
|
||||||
|
new ArrayList<>();
|
||||||
|
return new ShardMessageHeader(
|
||||||
|
message.getId(), message.getGroupId(), timestamp,
|
||||||
|
isLocal, read, status.isSent(), status.isSeen(),
|
||||||
|
attachmentHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ConversationMessageHeader> getMessageHeaders(
|
||||||
|
Transaction txn, ContactId contactId) throws DbException {
|
||||||
|
try {
|
||||||
|
Contact contact = db.getContact(txn, contactId);
|
||||||
|
GroupId contactGroupId = getContactGroup(contact).getId();
|
||||||
|
Map<MessageId, BdfDictionary> messages = clientHelper
|
||||||
|
.getMessageMetadataAsDictionary(txn, contactGroupId);
|
||||||
|
List<ConversationMessageHeader> headers =
|
||||||
|
new ArrayList<>();
|
||||||
|
for (Entry<MessageId, BdfDictionary> messageEntry : messages
|
||||||
|
.entrySet()) {
|
||||||
|
BdfDictionary meta = messageEntry.getValue();
|
||||||
|
if (meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue() ==
|
||||||
|
SHARD.getValue()) {
|
||||||
|
Message message = clientHelper
|
||||||
|
.getMessage(txn, messageEntry.getKey());
|
||||||
|
MessageStatus status = db.getMessageStatus(txn, contactId,
|
||||||
|
messageEntry.getKey());
|
||||||
|
headers.add(createShardMessageHeader(message, meta, status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<MessageId> getMessageIds(Transaction txn, ContactId contactId)
|
||||||
|
throws DbException {
|
||||||
|
Contact contact = db.getContact(txn, contactId);
|
||||||
|
GroupId contactGroupId = getContactGroup(contact).getId();
|
||||||
|
try {
|
||||||
|
Map<MessageId, BdfDictionary> messages = clientHelper
|
||||||
|
.getMessageMetadataAsDictionary(txn, contactGroupId);
|
||||||
|
return messages.keySet();
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeletionResult deleteAllMessages(Transaction txn, ContactId c)
|
||||||
|
throws DbException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeletionResult deleteMessages(Transaction txn, ContactId c,
|
||||||
|
Set<MessageId> messageIds) throws DbException {
|
||||||
|
DeletionResult result = new DeletionResult();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private void setContactId(Transaction txn, GroupId g, ContactId c)
|
private void setContactId(Transaction txn, GroupId g, ContactId c)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
BdfDictionary d = new BdfDictionary();
|
BdfDictionary d = new BdfDictionary();
|
||||||
@@ -323,14 +435,19 @@ class SocialBackupManagerImpl extends BdfIncomingMessageHook
|
|||||||
|
|
||||||
private void sendShardMessage(Transaction txn, Contact custodian,
|
private void sendShardMessage(Transaction txn, Contact custodian,
|
||||||
Shard shard) throws DbException, FormatException {
|
Shard shard) throws DbException, FormatException {
|
||||||
GroupId g = getContactGroup(custodian).getId();
|
Group group = getContactGroup(custodian);
|
||||||
|
GroupId g = group.getId();
|
||||||
|
if (!db.containsGroup(txn, g)) db.addGroup(txn, group);
|
||||||
long timestamp = clock.currentTimeMillis();
|
long timestamp = clock.currentTimeMillis();
|
||||||
byte[] body = messageEncoder.encodeShardMessage(shard);
|
byte[] body = messageEncoder.encodeShardMessage(shard);
|
||||||
Message m = clientHelper.createMessage(g, timestamp, body);
|
Message m = clientHelper.createMessage(g, timestamp, body);
|
||||||
BdfDictionary meta = BdfDictionary.of(
|
BdfDictionary meta = BdfDictionary.of(
|
||||||
new BdfEntry(MSG_KEY_MESSAGE_TYPE, SHARD.getValue()),
|
new BdfEntry(MSG_KEY_MESSAGE_TYPE, SHARD.getValue()),
|
||||||
new BdfEntry(MSG_KEY_LOCAL, true));
|
new BdfEntry(MSG_KEY_LOCAL, true),
|
||||||
|
new BdfEntry(MSG_KEY_TIMESTAMP, timestamp)
|
||||||
|
);
|
||||||
clientHelper.addLocalMessage(txn, m, meta, true, false);
|
clientHelper.addLocalMessage(txn, m, meta, true, false);
|
||||||
|
messageTracker.trackOutgoingMessage(txn, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendBackupMessage(Transaction txn, Contact custodian,
|
private void sendBackupMessage(Transaction txn, Contact custodian,
|
||||||
@@ -343,12 +460,17 @@ class SocialBackupManagerImpl extends BdfIncomingMessageHook
|
|||||||
BdfDictionary meta = BdfDictionary.of(
|
BdfDictionary meta = BdfDictionary.of(
|
||||||
new BdfEntry(MSG_KEY_MESSAGE_TYPE, BACKUP.getValue()),
|
new BdfEntry(MSG_KEY_MESSAGE_TYPE, BACKUP.getValue()),
|
||||||
new BdfEntry(MSG_KEY_LOCAL, true),
|
new BdfEntry(MSG_KEY_LOCAL, true),
|
||||||
|
new BdfEntry(MSG_KEY_TIMESTAMP, timestamp),
|
||||||
new BdfEntry(MSG_KEY_VERSION, version));
|
new BdfEntry(MSG_KEY_VERSION, version));
|
||||||
clientHelper.addLocalMessage(txn, m, meta, true, false);
|
clientHelper.addLocalMessage(txn, m, meta, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean localBackupExists(Transaction txn) throws DbException {
|
private boolean localBackupExists(Transaction txn) {
|
||||||
return !db.getGroupMetadata(txn, localGroup.getId()).isEmpty();
|
try {
|
||||||
|
return !db.getGroupMetadata(txn, localGroup.getId()).isEmpty();
|
||||||
|
} catch (DbException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
|||||||
import org.briarproject.bramble.api.sync.validation.ValidationManager;
|
import org.briarproject.bramble.api.sync.validation.ValidationManager;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
||||||
import org.briarproject.briar.api.socialbackup.DarkCrystal;
|
import org.briarproject.briar.api.conversation.ConversationManager;
|
||||||
import org.briarproject.briar.api.socialbackup.SocialBackupManager;
|
import org.briarproject.briar.api.socialbackup.SocialBackupManager;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -37,13 +37,15 @@ public class SocialBackupModule {
|
|||||||
ContactManager contactManager,
|
ContactManager contactManager,
|
||||||
ValidationManager validationManager,
|
ValidationManager validationManager,
|
||||||
ClientVersioningManager clientVersioningManager,
|
ClientVersioningManager clientVersioningManager,
|
||||||
SocialBackupManagerImpl socialBackupManager) {
|
SocialBackupManagerImpl socialBackupManager,
|
||||||
|
ConversationManager conversationManager) {
|
||||||
lifecycleManager.registerOpenDatabaseHook(socialBackupManager);
|
lifecycleManager.registerOpenDatabaseHook(socialBackupManager);
|
||||||
contactManager.registerContactHook(socialBackupManager);
|
contactManager.registerContactHook(socialBackupManager);
|
||||||
validationManager.registerIncomingMessageHook(CLIENT_ID,
|
validationManager.registerIncomingMessageHook(CLIENT_ID,
|
||||||
MAJOR_VERSION, socialBackupManager);
|
MAJOR_VERSION, socialBackupManager);
|
||||||
clientVersioningManager.registerClient(CLIENT_ID, MAJOR_VERSION,
|
clientVersioningManager.registerClient(CLIENT_ID, MAJOR_VERSION,
|
||||||
MINOR_VERSION, socialBackupManager);
|
MINOR_VERSION, socialBackupManager);
|
||||||
|
conversationManager.registerConversationClient(socialBackupManager);
|
||||||
return socialBackupManager;
|
return socialBackupManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,10 +90,4 @@ public class SocialBackupModule {
|
|||||||
MessageParser messageParser(MessageParserImpl messageParser) {
|
MessageParser messageParser(MessageParserImpl messageParser) {
|
||||||
return messageParser;
|
return messageParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
DarkCrystal darkCrystal(DarkCrystalStub darkCrystal) {
|
|
||||||
// TODO: Replace this with a real implementation
|
|
||||||
return darkCrystal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.briar.introduction;
|
|||||||
import org.briarproject.bramble.BrambleCoreModule;
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
||||||
import org.briarproject.briar.BriarCoreModule;
|
import org.briarproject.briar.BriarCoreModule;
|
||||||
|
import org.briarproject.briar.socialbackup.DefaultDarkCrystalModule;
|
||||||
import org.briarproject.briar.test.BriarIntegrationTestComponent;
|
import org.briarproject.briar.test.BriarIntegrationTestComponent;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -13,7 +14,8 @@ import dagger.Component;
|
|||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
BrambleCoreIntegrationTestModule.class,
|
BrambleCoreIntegrationTestModule.class,
|
||||||
BrambleCoreModule.class,
|
BrambleCoreModule.class,
|
||||||
BriarCoreModule.class
|
BriarCoreModule.class,
|
||||||
|
DefaultDarkCrystalModule.class
|
||||||
})
|
})
|
||||||
interface IntroductionIntegrationTestComponent
|
interface IntroductionIntegrationTestComponent
|
||||||
extends BriarIntegrationTestComponent {
|
extends BriarIntegrationTestComponent {
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
package org.briarproject.briar.socialbackup;
|
package org.briarproject.briar.socialbackup;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
|
import org.briarproject.bramble.api.sync.Group;
|
||||||
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfigModule;
|
import org.briarproject.bramble.test.TestDatabaseConfigModule;
|
||||||
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
|
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
|
||||||
import org.briarproject.briar.api.socialbackup.BackupMetadata;
|
import org.briarproject.briar.api.socialbackup.BackupMetadata;
|
||||||
|
import org.briarproject.briar.api.socialbackup.ShardMessageHeader;
|
||||||
import org.briarproject.briar.api.socialbackup.SocialBackupManager;
|
import org.briarproject.briar.api.socialbackup.SocialBackupManager;
|
||||||
import org.briarproject.briar.test.BriarIntegrationTest;
|
import org.briarproject.briar.test.BriarIntegrationTest;
|
||||||
import org.briarproject.briar.test.BriarIntegrationTestComponent;
|
import org.briarproject.briar.test.BriarIntegrationTestComponent;
|
||||||
@@ -10,23 +16,40 @@ import org.briarproject.briar.test.DaggerBriarIntegrationTestComponent;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class SocialBackupIntegrationTest
|
public class SocialBackupIntegrationTest
|
||||||
extends BriarIntegrationTest<BriarIntegrationTestComponent> {
|
extends BriarIntegrationTest<BriarIntegrationTestComponent> {
|
||||||
|
|
||||||
private SocialBackupManager socialBackupManager0;
|
private SocialBackupManager socialBackupManager0;
|
||||||
|
private SocialBackupManager socialBackupManager1;
|
||||||
|
private SocialBackupManager socialBackupManager2;
|
||||||
|
|
||||||
|
private Group g1From0;
|
||||||
|
private Group g0From1;
|
||||||
|
private Group g2From0;
|
||||||
|
private Group g0From2;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@Override
|
@Override
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
socialBackupManager0 = c0.getSocialBackupManager();
|
socialBackupManager0 = c0.getSocialBackupManager();
|
||||||
|
socialBackupManager1 = c1.getSocialBackupManager();
|
||||||
|
socialBackupManager2 = c2.getSocialBackupManager();
|
||||||
|
|
||||||
|
g1From0 = socialBackupManager0.getContactGroup(contact1From0);
|
||||||
|
g0From1 = socialBackupManager1.getContactGroup(contact0From1);
|
||||||
|
g2From0 = socialBackupManager0.getContactGroup(contact2From0);
|
||||||
|
g0From2 = socialBackupManager2.getContactGroup(contact0From2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -71,5 +94,89 @@ public class SocialBackupIntegrationTest
|
|||||||
// Sync the shard and backup messages to the contacts
|
// Sync the shard and backup messages to the contacts
|
||||||
sync0To1(2, true);
|
sync0To1(2, true);
|
||||||
sync0To2(2, true);
|
sync0To2(2, true);
|
||||||
|
|
||||||
|
Collection<ConversationMessageHeader> messages1At0 =
|
||||||
|
getMessages1At0();
|
||||||
|
assertEquals(1, messages1At0.size());
|
||||||
|
for (ConversationMessageHeader h : messages1At0) {
|
||||||
|
assertTrue(h instanceof ShardMessageHeader);
|
||||||
|
ShardMessageHeader s = (ShardMessageHeader) h;
|
||||||
|
assertTrue(s.isLocal());
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<ConversationMessageHeader> messages2At0 =
|
||||||
|
getMessages2At0();
|
||||||
|
assertEquals(1, messages2At0.size());
|
||||||
|
for (ConversationMessageHeader h : messages2At0) {
|
||||||
|
assertTrue(h instanceof ShardMessageHeader);
|
||||||
|
ShardMessageHeader s = (ShardMessageHeader) h;
|
||||||
|
assertTrue(s.isLocal());
|
||||||
|
}
|
||||||
|
|
||||||
|
// the shard message from 0 should have arrived at 1
|
||||||
|
Collection<ConversationMessageHeader> messages0At1 =
|
||||||
|
getMessages0At1();
|
||||||
|
assertEquals(1, messages0At1.size());
|
||||||
|
for (ConversationMessageHeader h : messages0At1) {
|
||||||
|
assertTrue(h instanceof ShardMessageHeader);
|
||||||
|
ShardMessageHeader s = (ShardMessageHeader) h;
|
||||||
|
assertFalse(s.isLocal());
|
||||||
|
}
|
||||||
|
db1.transaction(false, txn -> {
|
||||||
|
assertTrue(socialBackupManager1.amCustodian(txn, contactId0From1));
|
||||||
|
});
|
||||||
|
|
||||||
|
// the shard message from 0 should have arrived at 2
|
||||||
|
Collection<ConversationMessageHeader> messages0At2 =
|
||||||
|
getMessages0At2();
|
||||||
|
assertEquals(1, messages0At2.size());
|
||||||
|
for (ConversationMessageHeader h : messages0At2) {
|
||||||
|
assertTrue(h instanceof ShardMessageHeader);
|
||||||
|
ShardMessageHeader s = (ShardMessageHeader) h;
|
||||||
|
assertFalse(s.isLocal());
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert group counts
|
||||||
|
assertGroupCount(messageTracker0, g1From0.getId(), 1, 0);
|
||||||
|
assertGroupCount(messageTracker0, g2From0.getId(), 1, 0);
|
||||||
|
assertGroupCount(messageTracker1, g0From1.getId(), 1, 1);
|
||||||
|
assertGroupCount(messageTracker2, g0From2.getId(), 1, 1);
|
||||||
|
|
||||||
|
// mark a message as read
|
||||||
|
socialBackupManager1.setReadFlag(g0From1.getId(),
|
||||||
|
messages0At1.iterator().next().getId(), true);
|
||||||
|
assertGroupCount(messageTracker1, g0From1.getId(), 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Collection<ConversationMessageHeader> getMessages1At0()
|
||||||
|
throws DbException {
|
||||||
|
return db0.transactionWithResult(true, txn -> socialBackupManager0
|
||||||
|
.getMessageHeaders(txn, contactId1From0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<ConversationMessageHeader> getMessages2At0()
|
||||||
|
throws DbException {
|
||||||
|
return db0.transactionWithResult(true, txn -> socialBackupManager0
|
||||||
|
.getMessageHeaders(txn, contactId2From0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<ConversationMessageHeader> getMessages0At1()
|
||||||
|
throws DbException {
|
||||||
|
return db1.transactionWithResult(true, txn -> socialBackupManager1
|
||||||
|
.getMessageHeaders(txn, contactId0From1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<ConversationMessageHeader> getMessages0At2()
|
||||||
|
throws DbException {
|
||||||
|
return db1.transactionWithResult(true, txn -> socialBackupManager2
|
||||||
|
.getMessageHeaders(txn, contactId0From2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertGroupCount(MessageTracker tracker, GroupId g,
|
||||||
|
long msgCount, long unreadCount) throws DbException {
|
||||||
|
MessageTracker.GroupCount c1 = tracker.getGroupCount(g);
|
||||||
|
assertEquals(msgCount, c1.getMsgCount());
|
||||||
|
assertEquals(unreadCount, c1.getUnreadCount());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import org.briarproject.briar.messaging.MessagingModule;
|
|||||||
import org.briarproject.briar.privategroup.PrivateGroupModule;
|
import org.briarproject.briar.privategroup.PrivateGroupModule;
|
||||||
import org.briarproject.briar.privategroup.invitation.GroupInvitationModule;
|
import org.briarproject.briar.privategroup.invitation.GroupInvitationModule;
|
||||||
import org.briarproject.briar.sharing.SharingModule;
|
import org.briarproject.briar.sharing.SharingModule;
|
||||||
|
import org.briarproject.briar.socialbackup.DefaultDarkCrystalModule;
|
||||||
import org.briarproject.briar.socialbackup.SocialBackupModule;
|
import org.briarproject.briar.socialbackup.SocialBackupModule;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -47,7 +48,8 @@ import dagger.Component;
|
|||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
BrambleCoreIntegrationTestModule.class,
|
BrambleCoreIntegrationTestModule.class,
|
||||||
BrambleCoreModule.class,
|
BrambleCoreModule.class,
|
||||||
BriarCoreModule.class
|
BriarCoreModule.class,
|
||||||
|
DefaultDarkCrystalModule.class
|
||||||
})
|
})
|
||||||
public interface BriarIntegrationTestComponent
|
public interface BriarIntegrationTestComponent
|
||||||
extends BrambleCoreIntegrationTestEagerSingletons {
|
extends BrambleCoreIntegrationTestEagerSingletons {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import org.briarproject.briar.headless.contact.HeadlessContactModule
|
|||||||
import org.briarproject.briar.headless.event.HeadlessEventModule
|
import org.briarproject.briar.headless.event.HeadlessEventModule
|
||||||
import org.briarproject.briar.headless.forums.HeadlessForumModule
|
import org.briarproject.briar.headless.forums.HeadlessForumModule
|
||||||
import org.briarproject.briar.headless.messaging.HeadlessMessagingModule
|
import org.briarproject.briar.headless.messaging.HeadlessMessagingModule
|
||||||
|
import org.briarproject.briar.socialbackup.DefaultDarkCrystalModule
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Collections.emptyList
|
import java.util.Collections.emptyList
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@@ -37,6 +38,7 @@ import javax.inject.Singleton
|
|||||||
AccountModule::class,
|
AccountModule::class,
|
||||||
CircumventionModule::class,
|
CircumventionModule::class,
|
||||||
DefaultBatteryManagerModule::class,
|
DefaultBatteryManagerModule::class,
|
||||||
|
DefaultDarkCrystalModule::class, // FIXME: Real implementation needed
|
||||||
DefaultEventExecutorModule::class,
|
DefaultEventExecutorModule::class,
|
||||||
DefaultTaskSchedulerModule::class,
|
DefaultTaskSchedulerModule::class,
|
||||||
DefaultWakefulIoExecutorModule::class,
|
DefaultWakefulIoExecutorModule::class,
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import org.briarproject.bramble.api.db.DatabaseExecutor
|
|||||||
import org.briarproject.bramble.api.db.NoSuchContactException
|
import org.briarproject.bramble.api.db.NoSuchContactException
|
||||||
import org.briarproject.bramble.api.event.Event
|
import org.briarproject.bramble.api.event.Event
|
||||||
import org.briarproject.bramble.api.event.EventListener
|
import org.briarproject.bramble.api.event.EventListener
|
||||||
|
import org.briarproject.bramble.api.sync.MessageId
|
||||||
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent
|
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent
|
||||||
import org.briarproject.bramble.api.sync.event.MessagesSentEvent
|
import org.briarproject.bramble.api.sync.event.MessagesSentEvent
|
||||||
import org.briarproject.bramble.api.sync.MessageId
|
|
||||||
import org.briarproject.bramble.api.system.Clock
|
import org.briarproject.bramble.api.system.Clock
|
||||||
import org.briarproject.bramble.util.StringUtils.utf8IsTooLong
|
import org.briarproject.bramble.util.StringUtils.utf8IsTooLong
|
||||||
import org.briarproject.briar.api.blog.BlogInvitationRequest
|
import org.briarproject.briar.api.blog.BlogInvitationRequest
|
||||||
@@ -31,6 +31,7 @@ import org.briarproject.briar.api.messaging.PrivateMessageFactory
|
|||||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader
|
import org.briarproject.briar.api.messaging.PrivateMessageHeader
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse
|
||||||
|
import org.briarproject.briar.api.socialbackup.ShardMessageHeader
|
||||||
import org.briarproject.briar.headless.event.WebSocketController
|
import org.briarproject.briar.headless.event.WebSocketController
|
||||||
import org.briarproject.briar.headless.event.output
|
import org.briarproject.briar.headless.event.output
|
||||||
import org.briarproject.briar.headless.getContactIdFromPathParam
|
import org.briarproject.briar.headless.getContactIdFromPathParam
|
||||||
@@ -169,4 +170,6 @@ private class JsonVisitor(
|
|||||||
override fun visitIntroductionRequest(r: IntroductionRequest) = r.output(contactId)
|
override fun visitIntroductionRequest(r: IntroductionRequest) = r.output(contactId)
|
||||||
|
|
||||||
override fun visitIntroductionResponse(r: IntroductionResponse) = r.output(contactId)
|
override fun visitIntroductionResponse(r: IntroductionResponse) = r.output(contactId)
|
||||||
|
|
||||||
|
override fun visitShardMessage(r: ShardMessageHeader) = r.output(contactId)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.briarproject.briar.headless.contact.HeadlessContactModule
|
|||||||
import org.briarproject.briar.headless.event.HeadlessEventModule
|
import org.briarproject.briar.headless.event.HeadlessEventModule
|
||||||
import org.briarproject.briar.headless.forums.HeadlessForumModule
|
import org.briarproject.briar.headless.forums.HeadlessForumModule
|
||||||
import org.briarproject.briar.headless.messaging.HeadlessMessagingModule
|
import org.briarproject.briar.headless.messaging.HeadlessMessagingModule
|
||||||
|
import org.briarproject.briar.socialbackup.DefaultDarkCrystalModule
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Collections.emptyList
|
import java.util.Collections.emptyList
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@@ -34,6 +35,7 @@ import javax.inject.Singleton
|
|||||||
JavaSystemModule::class,
|
JavaSystemModule::class,
|
||||||
AccountModule::class,
|
AccountModule::class,
|
||||||
CircumventionModule::class,
|
CircumventionModule::class,
|
||||||
|
DefaultDarkCrystalModule::class,
|
||||||
DefaultEventExecutorModule::class,
|
DefaultEventExecutorModule::class,
|
||||||
DefaultTaskSchedulerModule::class,
|
DefaultTaskSchedulerModule::class,
|
||||||
DefaultWakefulIoExecutorModule::class,
|
DefaultWakefulIoExecutorModule::class,
|
||||||
|
|||||||
Reference in New Issue
Block a user