mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 03:09:04 +01:00
Resolve merge conflict with social-backup-poc
This commit is contained in:
@@ -50,7 +50,8 @@ public interface ContactManager {
|
||||
boolean active) throws DbException;
|
||||
|
||||
ContactId addContact(Transaction txn, Author remote, AuthorId local,
|
||||
PublicKey handshake, boolean verified) throws DbException;
|
||||
PublicKey handshake, boolean verified)
|
||||
throws DbException, GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Stores a contact associated with the given local and remote pseudonyms,
|
||||
@@ -209,6 +210,19 @@ public interface ContactManager {
|
||||
void setContactAlias(ContactId c, @Nullable String alias)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the contact's handshake public key
|
||||
*/
|
||||
void setHandshakePublicKey(Transaction txn, ContactId c,
|
||||
PublicKey handshakePublicKey) throws DbException,
|
||||
GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Sets the contact's handshake public key
|
||||
*/
|
||||
void setHandshakePublicKey(ContactId c, PublicKey handshakePublicKey)
|
||||
throws DbException, GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Returns true if a contact with this {@code remoteAuthorId} belongs to
|
||||
* the local pseudonym with this {@code localAuthorId}.
|
||||
|
||||
@@ -546,6 +546,11 @@ public interface DatabaseComponent extends TransactionManager {
|
||||
void setContactAlias(Transaction txn, ContactId c, @Nullable String alias)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the remote handshake public key for a given contact
|
||||
*/
|
||||
void setHandshakePublicKey(Transaction txn, ContactId c, PublicKey handshakePublicKey) throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the given group's visibility to the given contact.
|
||||
*/
|
||||
|
||||
@@ -33,11 +33,11 @@ dependencies {
|
||||
}
|
||||
|
||||
animalsniffer {
|
||||
// Allow requireNonNull: Android desugaring rewrites it (so it's safe for us to use),
|
||||
// and it gets used when passing method references instead of lambdas with Java 11.
|
||||
// Note that this line allows *all* methods from java.util.Objects.
|
||||
// That's the best that we can do with the configuration options that Animal Sniffer offers.
|
||||
ignore 'java.util.Objects'
|
||||
// Allow requireNonNull: Android desugaring rewrites it (so it's safe for us to use),
|
||||
// and it gets used when passing method references instead of lambdas with Java 11.
|
||||
// Note that this line allows *all* methods from java.util.Objects.
|
||||
// That's the best that we can do with the configuration options that Animal Sniffer offers.
|
||||
ignore 'java.util.Objects'
|
||||
}
|
||||
|
||||
// needed to make test output available to bramble-java
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.briarproject.bramble.connection;
|
||||
import org.briarproject.bramble.api.connection.ConnectionRegistry;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.HandshakeManager;
|
||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
@@ -50,7 +49,8 @@ class IncomingDuplexSyncConnection extends DuplexSyncConnection
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LOG.info("Running IncomingDuplexSyncConnection");
|
||||
LOG.info("Running IncomingDuplexSyncConnection on transport " +
|
||||
transportId.getString());
|
||||
// Read and recognise the tag
|
||||
StreamContext ctx = recogniseTag(reader, transportId);
|
||||
if (ctx == null) {
|
||||
@@ -65,10 +65,10 @@ class IncomingDuplexSyncConnection extends DuplexSyncConnection
|
||||
return;
|
||||
}
|
||||
if (ctx.isHandshakeMode()) {
|
||||
if (!performHandshake(ctx, contactId)) {
|
||||
LOG.warning("Handshake failed");
|
||||
return;
|
||||
}
|
||||
if (!performHandshake(ctx, contactId)) {
|
||||
LOG.warning("Handshake failed");
|
||||
return;
|
||||
}
|
||||
// Allocate a rotation mode stream context
|
||||
ctx = allocateStreamContext(contactId, transportId);
|
||||
if (ctx == null) {
|
||||
|
||||
@@ -61,7 +61,8 @@ class OutgoingDuplexSyncConnection extends DuplexSyncConnection
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LOG.info("Running OutgoingDuplexSyncConnection");
|
||||
LOG.info("Running OutgoingDuplexSyncConnection on transport " +
|
||||
transportId.getString());
|
||||
// Allocate a stream context
|
||||
StreamContext ctx = allocateStreamContext(contactId, transportId);
|
||||
if (ctx == null) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.briarproject.bramble.api.contact.PendingContact;
|
||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||
import org.briarproject.bramble.api.contact.PendingContactState;
|
||||
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent;
|
||||
import org.briarproject.bramble.api.crypto.CryptoConstants;
|
||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
@@ -121,9 +122,12 @@ class ContactManagerImpl implements ContactManager, EventListener {
|
||||
|
||||
@Override
|
||||
public ContactId addContact(Transaction txn, Author remote, AuthorId local,
|
||||
PublicKey handshake, boolean verified) throws DbException {
|
||||
PublicKey handshake, boolean verified)
|
||||
throws DbException, GeneralSecurityException {
|
||||
ContactId c = db.addContact(txn, remote, local, handshake, verified);
|
||||
Contact contact = db.getContact(txn, c);
|
||||
KeyPair ourKeyPair = identityManager.getHandshakeKeys(txn);
|
||||
keyManager.addContact(txn, c, handshake, ourKeyPair);
|
||||
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
||||
return c;
|
||||
}
|
||||
@@ -243,6 +247,25 @@ class ContactManagerImpl implements ContactManager, EventListener {
|
||||
db.transaction(false, txn -> setContactAlias(txn, c, alias));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHandshakePublicKey(Transaction txn, ContactId c,
|
||||
PublicKey handshakePublicKey) throws DbException, GeneralSecurityException {
|
||||
if (handshakePublicKey.getKeyType() !=
|
||||
CryptoConstants.KEY_TYPE_AGREEMENT) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
db.setHandshakePublicKey(txn, c, handshakePublicKey);
|
||||
KeyPair ourKeyPair = identityManager.getHandshakeKeys(txn);
|
||||
keyManager.addContact(txn, c, handshakePublicKey, ourKeyPair);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHandshakePublicKey(ContactId c, PublicKey handshakePublicKey)
|
||||
throws DbException, GeneralSecurityException {
|
||||
db.transaction(false,
|
||||
txn -> setHandshakePublicKey(txn, c, handshakePublicKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contactExists(Transaction txn, AuthorId remoteAuthorId,
|
||||
AuthorId localAuthorId) throws DbException {
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.briarproject.bramble.api.transport.KeySetId;
|
||||
import org.briarproject.bramble.api.transport.TransportKeySet;
|
||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -695,6 +696,11 @@ interface Database<T> {
|
||||
void setHandshakeKeyPair(T txn, AuthorId local, PublicKey publicKey,
|
||||
PrivateKey privateKey) throws DbException;
|
||||
|
||||
/**
|
||||
* Sets the handshake public key for a given contact
|
||||
*/
|
||||
void setHandshakePublicKey(T txn, ContactId c, PublicKey handshakePublicKey) throws DbException;
|
||||
|
||||
/**
|
||||
* Marks the given message as permanent, i.e. not temporary.
|
||||
*/
|
||||
|
||||
@@ -1040,6 +1040,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHandshakePublicKey(Transaction transaction, ContactId c, PublicKey handshakePublicKey) throws DbException {
|
||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsContact(txn, c))
|
||||
throw new NoSuchContactException();
|
||||
db.setHandshakePublicKey(txn, c, handshakePublicKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHandshakeKeyPair(Transaction transaction, AuthorId local,
|
||||
PublicKey publicKey, PrivateKey privateKey) throws DbException {
|
||||
|
||||
@@ -3058,6 +3058,23 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHandshakePublicKey(Connection txn, ContactId c, PublicKey handshakePublicKey) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
String sql = "UPDATE contacts SET handshakePublicKey = ? WHERE contactId = ?";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setBytes(1, handshakePublicKey.getEncoded());
|
||||
ps.setInt(2, c.getInt());
|
||||
int affected = ps.executeUpdate();
|
||||
if (affected < 0 || affected > 1) throw new DbStateException();
|
||||
ps.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupVisibility(Connection txn, ContactId c, GroupId g,
|
||||
boolean shared) throws DbException {
|
||||
|
||||
@@ -387,6 +387,13 @@ public class ConversationActivity extends BriarActivity
|
||||
}
|
||||
});
|
||||
|
||||
// enable help recover account action if available
|
||||
observeOnce(viewModel.amCustodian(), this, enable -> {
|
||||
if (enable) {
|
||||
menu.findItem(R.id.action_help_recover_account).setEnabled(true);
|
||||
}
|
||||
});
|
||||
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.briarproject.briar.api.messaging.PrivateMessageFactory;
|
||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||
import org.briarproject.briar.api.messaging.event.AttachmentReceivedEvent;
|
||||
import org.briarproject.briar.api.remotewipe.RemoteWipeManager;
|
||||
import org.briarproject.briar.api.socialbackup.SocialBackupManager;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -86,6 +87,7 @@ public class ConversationViewModel extends DbViewModel
|
||||
private final AttachmentRetriever attachmentRetriever;
|
||||
private final AttachmentCreator attachmentCreator;
|
||||
private final RemoteWipeManager remoteWipeManager;
|
||||
private final SocialBackupManager socialBackupManager;
|
||||
|
||||
@Nullable
|
||||
private ContactId contactId = null;
|
||||
@@ -108,6 +110,7 @@ public class ConversationViewModel extends DbViewModel
|
||||
new MutableLiveEvent<>();
|
||||
private final MutableLiveData<Boolean> amRemoteWiper = new MutableLiveData<>();
|
||||
private final MutableLiveData<Boolean> isRemoteWiper = new MutableLiveData<>();
|
||||
private final MutableLiveData<Boolean> amCustodian = new MutableLiveData<>();
|
||||
|
||||
@Inject
|
||||
ConversationViewModel(Application application,
|
||||
@@ -123,7 +126,8 @@ public class ConversationViewModel extends DbViewModel
|
||||
PrivateMessageFactory privateMessageFactory,
|
||||
AttachmentRetriever attachmentRetriever,
|
||||
RemoteWipeManager remoteWipeManager,
|
||||
AttachmentCreator attachmentCreator) {
|
||||
AttachmentCreator attachmentCreator,
|
||||
SocialBackupManager socialBackupManager) {
|
||||
super(application, dbExecutor, lifecycleManager, db, androidExecutor);
|
||||
this.db = db;
|
||||
this.eventBus = eventBus;
|
||||
@@ -135,6 +139,7 @@ public class ConversationViewModel extends DbViewModel
|
||||
this.attachmentRetriever = attachmentRetriever;
|
||||
this.attachmentCreator = attachmentCreator;
|
||||
this.remoteWipeManager = remoteWipeManager;
|
||||
this.socialBackupManager = socialBackupManager;
|
||||
messagingGroupId = map(contactItem, c ->
|
||||
messagingManager.getContactGroup(c.getContact()).getId());
|
||||
contactDeleted.setValue(false);
|
||||
@@ -311,6 +316,10 @@ public class ConversationViewModel extends DbViewModel
|
||||
boolean isWiper = db.transactionWithResult(true,
|
||||
txn -> remoteWipeManager.isWiper(txn, c));
|
||||
isRemoteWiper.postValue(isWiper);
|
||||
// Check if we are a social backup custodian for this contact
|
||||
boolean amCustodianBool = db.transactionWithResult(true,
|
||||
txn -> socialBackupManager.amCustodian(txn, c));
|
||||
amCustodian.postValue(amCustodianBool);
|
||||
}
|
||||
|
||||
@DatabaseExecutor
|
||||
@@ -404,6 +413,10 @@ public class ConversationViewModel extends DbViewModel
|
||||
return isRemoteWiper;
|
||||
}
|
||||
|
||||
LiveData<Boolean> amCustodian() {
|
||||
return amCustodian;
|
||||
}
|
||||
|
||||
@UiThread
|
||||
void recheckFeaturesAndOnboarding(ContactId contactId) {
|
||||
runOnDbThread(() -> {
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.briar.R;
|
||||
@@ -29,6 +30,9 @@ public class DistributedBackupActivity extends BriarActivity implements
|
||||
@Inject
|
||||
public SocialBackupManager socialBackupManager;
|
||||
|
||||
@Inject
|
||||
public ContactManager contactManager;
|
||||
|
||||
@Inject
|
||||
public DatabaseComponent db;
|
||||
|
||||
@@ -52,6 +56,20 @@ public class DistributedBackupActivity extends BriarActivity implements
|
||||
showInitialFragment(fragment);
|
||||
});
|
||||
} catch (DbException e) {
|
||||
// Check the number of contacts in the contacts list > 1
|
||||
try {
|
||||
if (contactManager.getContacts().size() < 2) {
|
||||
Toast.makeText(this,
|
||||
R.string.social_backup_not_enough_contacts,
|
||||
Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
} catch (DbException dbException) {
|
||||
Toast.makeText(this,
|
||||
R.string.reading_contacts_error,
|
||||
Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
CustodianSelectorFragment fragment =
|
||||
CustodianSelectorFragment.newInstance();
|
||||
showInitialFragment(fragment);
|
||||
|
||||
@@ -64,17 +64,13 @@ public class ThresholdSelectorFragment extends BaseFragment {
|
||||
message = view.findViewById(R.id.textViewMessage);
|
||||
mOfn = view.findViewById(R.id.textViewmOfn);
|
||||
|
||||
if (numberOfCustodians == 2) {
|
||||
message.setText(R.string.threshold_too_few_custodians);
|
||||
}
|
||||
if (numberOfCustodians > 3) {
|
||||
seekBar.setMax(numberOfCustodians -3);
|
||||
seekBar.setProgress(threshold - 2);
|
||||
seekBar.setOnSeekBarChangeListener(new SeekBarListener());
|
||||
recommendedThreshold =
|
||||
SecretSharingWrapper.defaultThreshold(numberOfCustodians);
|
||||
threshold = recommendedThreshold;
|
||||
|
||||
seekBar.setProgress(threshold - 2);
|
||||
} else {
|
||||
seekBar.setEnabled(false);
|
||||
threshold = 2;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.briarproject.briar.android.socialbackup.recover;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
@@ -14,6 +16,7 @@ import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||
import org.briarproject.briar.android.contact.add.nearby.QrCodeUtils;
|
||||
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
||||
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
|
||||
import org.briarproject.briar.api.socialbackup.MessageEncoder;
|
||||
import org.briarproject.briar.api.socialbackup.ReturnShardPayload;
|
||||
import org.briarproject.briar.api.socialbackup.recovery.RestoreAccount;
|
||||
import org.briarproject.briar.api.socialbackup.recovery.SecretOwnerTask;
|
||||
@@ -22,6 +25,7 @@ import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -50,6 +54,7 @@ class OwnerReturnShardViewModel extends AndroidViewModel
|
||||
private final Executor ioExecutor;
|
||||
private final SecretOwnerTask task;
|
||||
private final RestoreAccount restoreAccount;
|
||||
private final SharedPreferences prefs;
|
||||
|
||||
private final MutableLiveEvent<Boolean> errorTryAgain =
|
||||
new MutableLiveEvent<>();
|
||||
@@ -65,18 +70,26 @@ class OwnerReturnShardViewModel extends AndroidViewModel
|
||||
private Bitmap qrCodeBitmap;
|
||||
private WifiManager wifiManager;
|
||||
private SecretKey secretKey;
|
||||
private final MessageEncoder messageEncoder;
|
||||
|
||||
@Inject
|
||||
OwnerReturnShardViewModel(Application app,
|
||||
AndroidExecutor androidExecutor,
|
||||
SecretOwnerTask task,
|
||||
RestoreAccount restoreAccount,
|
||||
@IoExecutor Executor ioExecutor) {
|
||||
@IoExecutor Executor ioExecutor,
|
||||
MessageEncoder messageEncoder) {
|
||||
super(app);
|
||||
this.androidExecutor = androidExecutor;
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.restoreAccount = restoreAccount;
|
||||
this.messageEncoder = messageEncoder;
|
||||
this.task = task;
|
||||
this.prefs = app.getSharedPreferences("account-recovery",
|
||||
Context.MODE_PRIVATE);
|
||||
restoreAccount.restoreFromPrevious(prefs.getStringSet("recovered", new HashSet<>()));
|
||||
|
||||
|
||||
wifiManager = (WifiManager) app.getSystemService(WIFI_SERVICE);
|
||||
|
||||
// IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED);
|
||||
@@ -144,13 +157,6 @@ class OwnerReturnShardViewModel extends AndroidViewModel
|
||||
ioExecutor.execute(() -> {
|
||||
task.start(this, getWifiIpv4Address());
|
||||
});
|
||||
// KeyAgreementTask oldTask = task;
|
||||
// KeyAgreementTask newTask = keyAgreementTaskProvider.get();
|
||||
// task = newTask;
|
||||
// ioExecutor.execute(() -> {
|
||||
// if (oldTask != null) oldTask.stopListening();
|
||||
// newTask.listen();
|
||||
// });
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@@ -218,16 +224,18 @@ class OwnerReturnShardViewModel extends AndroidViewModel
|
||||
this.state.postValue(state);
|
||||
});
|
||||
} else if (state instanceof SecretOwnerTask.State.Success) {
|
||||
// startClicked.setEvent(true);
|
||||
this.state.postValue(state);
|
||||
// TODO do same for failure
|
||||
} else {
|
||||
this.state.postValue(state);
|
||||
}
|
||||
}
|
||||
|
||||
public RestoreAccount.AddReturnShardPayloadResult addToShardSet(ReturnShardPayload toAdd) {
|
||||
return restoreAccount.addReturnShardPayload(toAdd);
|
||||
RestoreAccount.AddReturnShardPayloadResult result = restoreAccount.addReturnShardPayload(toAdd);
|
||||
if (result == RestoreAccount.AddReturnShardPayloadResult.OK) {
|
||||
prefs.edit().putStringSet("recovered", restoreAccount.getEncodedShards()).apply();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean canRecover() {
|
||||
|
||||
@@ -52,9 +52,11 @@ public class RestoreAccountActivity extends BaseActivity
|
||||
showInitialFragment(RestoreAccountSetPasswordFragment.newInstance());
|
||||
} else if (state == State.DOZE) {
|
||||
showDozeFragment();
|
||||
} else if (state == State.CREATED || state == State.FAILED) {
|
||||
// TODO: Show an error if failed
|
||||
} else if (state == State.CREATED) {
|
||||
showApp();
|
||||
} else { // FAILED
|
||||
// TODO: Show an error if failed
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.briarproject.briar.android.socialbackup.recover;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import org.briarproject.bramble.api.account.AccountManager;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
@@ -45,27 +47,27 @@ class RestoreAccountViewModel extends AndroidViewModel {
|
||||
new MutableLiveData<>(false);
|
||||
|
||||
private final AccountManager accountManager;
|
||||
private final ContactManager contactManager;
|
||||
private final Executor ioExecutor;
|
||||
private final PasswordStrengthEstimator strengthEstimator;
|
||||
private final DozeHelper dozeHelper;
|
||||
private final RestoreAccount restoreAccount;
|
||||
private final SharedPreferences prefs;
|
||||
|
||||
@Inject
|
||||
RestoreAccountViewModel(Application app,
|
||||
AccountManager accountManager,
|
||||
ContactManager contactManager,
|
||||
RestoreAccount restoreAccount,
|
||||
@IoExecutor Executor ioExecutor,
|
||||
PasswordStrengthEstimator strengthEstimator,
|
||||
DozeHelper dozeHelper) {
|
||||
super(app);
|
||||
this.accountManager = accountManager;
|
||||
this.contactManager = contactManager;
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.strengthEstimator = strengthEstimator;
|
||||
this.dozeHelper = dozeHelper;
|
||||
this.restoreAccount = restoreAccount;
|
||||
this.prefs = app.getSharedPreferences("account-recovery",
|
||||
Context.MODE_PRIVATE);
|
||||
|
||||
ioExecutor.execute(() -> {
|
||||
if (accountManager.accountExists()) {
|
||||
@@ -112,17 +114,24 @@ class RestoreAccountViewModel extends AndroidViewModel {
|
||||
if (socialBackup == null) {
|
||||
LOG.warning("Cannot retrieve social backup");
|
||||
state.postEvent(State.FAILED);
|
||||
return;
|
||||
}
|
||||
Identity identity = socialBackup.getIdentity();
|
||||
ioExecutor.execute(() -> {
|
||||
if (accountManager.restoreAccount(identity, password)) {
|
||||
LOG.info("Restored account");
|
||||
try {
|
||||
restoreAccount.addContactsToDb();
|
||||
restoreAccount.restoreAccountWhenDatabaseReady();
|
||||
} catch (DbException e) {
|
||||
LOG.warning("Cannot retrieve social backup");
|
||||
LOG.warning("Failure processing social backup");
|
||||
e.printStackTrace();
|
||||
state.postEvent(State.FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove partial recovery from shared preferences
|
||||
prefs.edit().clear().apply();
|
||||
|
||||
state.postEvent(State.CREATED);
|
||||
} else {
|
||||
LOG.warning("Failed to create account");
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
android:id="@+id/action_help_recover_account"
|
||||
android:icon="@drawable/introduction_white"
|
||||
android:title="@string/help_recover_account"
|
||||
android:enabled="false"
|
||||
app:showAsAction="never"/>
|
||||
|
||||
<item
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<string name="setup_name_explanation">Your nickname will be shown next to any content you post. You can\'t change it after creating your account.</string>
|
||||
<string name="setup_next">Next</string>
|
||||
<string name="setup_password_intro">Choose a Password</string>
|
||||
<string name="setup_password_explanation">Your Briar account is stored encrypted on your device, not in the cloud. If you forget your password or uninstall Briar, there\'s no way to recover your account.\n\nChoose a long password that\'s hard to guess, such as four random words, or ten random letters, numbers and symbols.</string>
|
||||
<string name="setup_password_explanation">Your Briar account is stored encrypted on your device, not in the cloud. If you forget your password or uninstall Briar, you can only recover your account if you have made a social backup.\n\nChoose a long password that\'s hard to guess, such as four random words, or ten random letters, numbers and symbols.</string>
|
||||
<string name="setup_doze_title">Background Connections</string>
|
||||
<string name="setup_doze_intro">To receive messages, Briar needs to stay connected in the background.</string>
|
||||
<string name="setup_doze_explanation">To receive messages, Briar needs to stay connected in the background. Please disable battery optimizations so Briar can stay connected.</string>
|
||||
@@ -37,7 +37,7 @@
|
||||
<string name="sign_in_button">Sign In</string>
|
||||
<string name="forgotten_password">I have forgotten my password</string>
|
||||
<string name="dialog_title_lost_password">Lost Password</string>
|
||||
<string name="dialog_message_lost_password">Your Briar account is stored encrypted on your device, not in the cloud, so we can\'t reset your password. Would you like to delete your account and start again?\n\nCaution: Your identities, contacts and messages will be permanently lost.</string>
|
||||
<string name="dialog_message_lost_password">Your Briar account is stored encrypted on your device, not in the cloud, so we can\'t reset your password. If you have made a social backup, you can delete your account and set a new password when you restore it. Would you like to delete your account and start again?\n\nCaution: Your identities, contacts and messages will be permanently lost if you do not have a backup.</string>
|
||||
<string name="startup_failed_notification_title">Briar could not start</string>
|
||||
<string name="startup_failed_notification_text">Tap for more information.</string>
|
||||
<string name="startup_failed_activity_title">Briar Startup Failure</string>
|
||||
@@ -664,7 +664,6 @@
|
||||
<string name="threshold_recommended">Secure - recommended threshold</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_too_few_custodians">Danger of loss - more contacts recommended</string>
|
||||
<string name="threshold_defined">Choose Threshold</string>
|
||||
<string name="threshold_m_of_n">%d of %d contacts needed to recover your account</string>
|
||||
|
||||
@@ -730,6 +729,9 @@
|
||||
<string name="activity_name_custodian_help_recovery">Help recover account</string>
|
||||
<string name="existing_backup_explain">%d of the following contacts are needed to restore your account:</string>
|
||||
|
||||
<string name="social_backup_not_enough_contacts">To make a social backup, you need at least 2 contacts in your contacts list</string>
|
||||
<string name="reading_contacts_error">There was an error reading your contacts list</string>
|
||||
|
||||
<!-- Remote Wipe -->
|
||||
|
||||
<!-- setup -->
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.briarproject.briar.api.handshakekeyexchange;
|
||||
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
import org.briarproject.briar.api.conversation.ConversationManager;
|
||||
|
||||
public interface HandshakeKeyExchangeManager extends ConversationManager.ConversationClient {
|
||||
|
||||
/**
|
||||
* The unique ID of the client.
|
||||
*/
|
||||
ClientId CLIENT_ID = new ClientId("org.briarproject.briar.handshakekeyexchange");
|
||||
|
||||
/**
|
||||
* The current major version of the handshake key exchange client.
|
||||
*/
|
||||
int MAJOR_VERSION = 0;
|
||||
|
||||
/**
|
||||
* The current minor version of the handshake key exchange client.
|
||||
*/
|
||||
int MINOR_VERSION = 0;
|
||||
}
|
||||
@@ -1,17 +1,22 @@
|
||||
package org.briarproject.briar.api.socialbackup;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Identity;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SocialBackup {
|
||||
private Identity identity;
|
||||
private List<ContactData> contacts;
|
||||
private Map<TransportId, TransportProperties> localTransportProperties;
|
||||
private int version;
|
||||
|
||||
public SocialBackup (Identity identity, List<ContactData> contacts, int version) {
|
||||
public SocialBackup (Identity identity, List<ContactData> contacts, Map<TransportId, TransportProperties> localTransportProperties, int version) {
|
||||
this.identity = identity;
|
||||
this.contacts = contacts;
|
||||
this.localTransportProperties = localTransportProperties;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@@ -23,6 +28,10 @@ public class SocialBackup {
|
||||
return contacts;
|
||||
}
|
||||
|
||||
public Map<TransportId, TransportProperties> getLocalTransportProperties() {
|
||||
return localTransportProperties;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@@ -6,17 +6,21 @@ import org.briarproject.briar.api.socialbackup.ReturnShardPayload;
|
||||
import org.briarproject.briar.api.socialbackup.SocialBackup;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Set;
|
||||
|
||||
public interface RestoreAccount {
|
||||
|
||||
enum AddReturnShardPayloadResult {
|
||||
DUPLICATE,
|
||||
MISMATCH,
|
||||
OK
|
||||
OK,
|
||||
RECOVERED
|
||||
}
|
||||
|
||||
int getNumberOfShards();
|
||||
|
||||
Set<String> getEncodedShards();
|
||||
|
||||
AddReturnShardPayloadResult addReturnShardPayload(ReturnShardPayload toAdd);
|
||||
|
||||
boolean canRecover();
|
||||
@@ -25,5 +29,11 @@ public interface RestoreAccount {
|
||||
|
||||
SocialBackup getSocialBackup();
|
||||
|
||||
void addContactsToDb() throws DbException;
|
||||
// void addContactsToDb() throws DbException;
|
||||
|
||||
void restoreFromPrevious(Set<String> previousShards);
|
||||
|
||||
void restoreAccountWhenDatabaseReady() throws DbException;
|
||||
|
||||
// void addLocalTransportProperties() throws DbException;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.briarproject.briar.avatar.AvatarModule;
|
||||
import org.briarproject.briar.blog.BlogModule;
|
||||
import org.briarproject.briar.feed.FeedModule;
|
||||
import org.briarproject.briar.forum.ForumModule;
|
||||
import org.briarproject.briar.handshakekeyexchange.HandshakeKeyExchangeModule;
|
||||
import org.briarproject.briar.identity.IdentityModule;
|
||||
import org.briarproject.briar.introduction.IntroductionModule;
|
||||
import org.briarproject.briar.messaging.MessagingModule;
|
||||
@@ -12,7 +13,6 @@ import org.briarproject.briar.privategroup.invitation.GroupInvitationModule;
|
||||
import org.briarproject.briar.remotewipe.RemoteWipeModule;
|
||||
import org.briarproject.briar.sharing.SharingModule;
|
||||
import org.briarproject.briar.socialbackup.SocialBackupModule;
|
||||
//import org.briarproject.briar.socialbackup.DefaultSocialBackupModule;
|
||||
|
||||
public interface BriarCoreEagerSingletons {
|
||||
|
||||
@@ -40,6 +40,8 @@ public interface BriarCoreEagerSingletons {
|
||||
|
||||
void inject(RemoteWipeModule.EagerSingletons init);
|
||||
|
||||
void inject(HandshakeKeyExchangeModule.EagerSingletons init);
|
||||
|
||||
class Helper {
|
||||
|
||||
public static void injectEagerSingletons(BriarCoreEagerSingletons c) {
|
||||
@@ -55,6 +57,7 @@ public interface BriarCoreEagerSingletons {
|
||||
c.inject(new IntroductionModule.EagerSingletons());
|
||||
c.inject(new SocialBackupModule.EagerSingletons());
|
||||
c.inject(new RemoteWipeModule.EagerSingletons());
|
||||
c.inject(new HandshakeKeyExchangeModule.EagerSingletons());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.briarproject.briar.client.BriarClientModule;
|
||||
import org.briarproject.briar.feed.DnsModule;
|
||||
import org.briarproject.briar.feed.FeedModule;
|
||||
import org.briarproject.briar.forum.ForumModule;
|
||||
import org.briarproject.briar.handshakekeyexchange.HandshakeKeyExchangeModule;
|
||||
import org.briarproject.briar.identity.IdentityModule;
|
||||
import org.briarproject.briar.introduction.IntroductionModule;
|
||||
import org.briarproject.briar.messaging.MessagingModule;
|
||||
@@ -35,6 +36,7 @@ import dagger.Module;
|
||||
RemoteWipeModule.class,
|
||||
SharingModule.class,
|
||||
SocialBackupModule.class,
|
||||
HandshakeKeyExchangeModule.class,
|
||||
TestModule.class
|
||||
})
|
||||
public class BriarCoreModule {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.briarproject.briar.handshakekeyexchange;
|
||||
|
||||
public interface HandshakeKeyExchangeConstants {
|
||||
|
||||
// Group metadata keys
|
||||
String GROUP_KEY_CONTACT_ID = "contactId";
|
||||
|
||||
// Message metadata keys
|
||||
String MSG_KEY_TIMESTAMP = "timestamp";
|
||||
String MSG_KEY_MESSAGE_TYPE = "messageType";
|
||||
String MSG_KEY_LOCAL = "local";
|
||||
String MSG_KEY_VERSION = "version";
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
package org.briarproject.briar.handshakekeyexchange;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.client.ClientHelper;
|
||||
import org.briarproject.bramble.api.client.ContactGroupFactory;
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.crypto.AgreementPublicKey;
|
||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||
import org.briarproject.bramble.api.data.BdfEntry;
|
||||
import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.data.MetadataParser;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
||||
import org.briarproject.briar.api.client.MessageTracker;
|
||||
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
|
||||
import org.briarproject.briar.api.conversation.DeletionResult;
|
||||
import org.briarproject.briar.api.handshakekeyexchange.HandshakeKeyExchangeManager;
|
||||
import org.briarproject.briar.client.ConversationClientImpl;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.briar.handshakekeyexchange.HandshakeKeyExchangeConstants.GROUP_KEY_CONTACT_ID;
|
||||
import static org.briarproject.briar.handshakekeyexchange.HandshakeKeyExchangeConstants.MSG_KEY_LOCAL;
|
||||
import static org.briarproject.briar.handshakekeyexchange.HandshakeKeyExchangeConstants.MSG_KEY_TIMESTAMP;
|
||||
|
||||
public class HandshakeKeyExchangeManagerImpl extends ConversationClientImpl
|
||||
implements
|
||||
HandshakeKeyExchangeManager, LifecycleManager.OpenDatabaseHook,
|
||||
ContactManager.ContactHook,
|
||||
ClientVersioningManager.ClientVersioningHook {
|
||||
|
||||
private final ClientVersioningManager clientVersioningManager;
|
||||
private final ContactGroupFactory contactGroupFactory;
|
||||
private final ContactManager contactManager;
|
||||
private final IdentityManager identityManager;
|
||||
private final Group localGroup;
|
||||
private final Clock clock;
|
||||
private PublicKey handshakePublicKey;
|
||||
private static final Logger LOG =
|
||||
getLogger(HandshakeKeyExchangeManager.class.getName());
|
||||
|
||||
|
||||
@Inject
|
||||
protected HandshakeKeyExchangeManagerImpl(
|
||||
DatabaseComponent db,
|
||||
ClientHelper clientHelper,
|
||||
MetadataParser metadataParser,
|
||||
MessageTracker messageTracker,
|
||||
ClientVersioningManager clientVersioningManager,
|
||||
ContactGroupFactory contactGroupFactory,
|
||||
ContactManager contactManager,
|
||||
IdentityManager identityManager,
|
||||
Clock clock
|
||||
) {
|
||||
super(db, clientHelper, metadataParser, messageTracker);
|
||||
this.clientVersioningManager = clientVersioningManager;
|
||||
this.contactGroupFactory = contactGroupFactory;
|
||||
this.contactManager = contactManager;
|
||||
this.identityManager = identityManager;
|
||||
this.clock = clock;
|
||||
localGroup =
|
||||
contactGroupFactory.createLocalGroup(CLIENT_ID, MAJOR_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDatabaseOpened(Transaction txn) throws DbException {
|
||||
// Get our own handshake public key
|
||||
handshakePublicKey = identityManager.getHandshakeKeys(txn).getPublic();
|
||||
|
||||
if (!db.containsGroup(txn, localGroup.getId())) {
|
||||
db.addGroup(txn, localGroup);
|
||||
|
||||
// Set things up for any pre-existing contacts
|
||||
for (Contact c : db.getContacts(txn)) addingContact(txn, c);
|
||||
} else {
|
||||
for (Contact c : db.getContacts(txn)) {
|
||||
if (c.getHandshakePublicKey() == null) {
|
||||
sendHandshakePublicKey(txn, c);
|
||||
} else {
|
||||
LOG.info("Have pk for contact " + c.getAuthor().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Group getContactGroup(Contact c) {
|
||||
return contactGroupFactory.createContactGroup(CLIENT_ID,
|
||||
MAJOR_VERSION, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ConversationMessageHeader> getMessageHeaders(
|
||||
Transaction txn, ContactId contactId) throws DbException {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@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 {
|
||||
GroupId g = getContactGroup(db.getContact(txn, c)).getId();
|
||||
for (MessageId messageId : db.getMessageIds(txn, g)) {
|
||||
db.deleteMessage(txn, messageId);
|
||||
db.deleteMessageMetadata(txn, messageId);
|
||||
}
|
||||
messageTracker.initializeGroupCount(txn, g);
|
||||
return new DeletionResult();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DeletionResult deleteMessages(Transaction txn, ContactId c,
|
||||
Set<MessageId> messageIds) throws DbException {
|
||||
for (MessageId m : messageIds) {
|
||||
db.deleteMessage(txn, m);
|
||||
db.deleteMessageMetadata(txn, m);
|
||||
}
|
||||
return new DeletionResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
|
||||
BdfDictionary meta) throws DbException, FormatException {
|
||||
LOG.info("Incoming HandshakeKeyExchange message");
|
||||
ContactId contactId = getContactId(txn, m.getGroupId());
|
||||
Contact c = contactManager.getContact(txn, contactId);
|
||||
if (c.getHandshakePublicKey() != null) {
|
||||
LOG.info("Already have public key - ignoring message");
|
||||
return false;
|
||||
}
|
||||
LOG.info("Adding contact's handshake public key");
|
||||
PublicKey handshakePublicKey = new AgreementPublicKey(body.getRaw(0));
|
||||
|
||||
try {
|
||||
contactManager
|
||||
.setHandshakePublicKey(txn, contactId, handshakePublicKey);
|
||||
} catch (GeneralSecurityException e) {
|
||||
LOG.warning("Security exception when adding remote handshake public key");
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private ContactId getContactId(Transaction txn, GroupId g)
|
||||
throws DbException {
|
||||
try {
|
||||
BdfDictionary meta =
|
||||
clientHelper.getGroupMetadataAsDictionary(txn, g);
|
||||
return new ContactId(meta.getLong(
|
||||
HandshakeKeyExchangeConstants.GROUP_KEY_CONTACT_ID)
|
||||
.intValue());
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addingContact(Transaction txn, Contact c) throws DbException {
|
||||
// Create a group to share with the contact
|
||||
Group g = getContactGroup(c);
|
||||
db.addGroup(txn, g);
|
||||
// Apply the client's visibility to the contact group
|
||||
Group.Visibility client =
|
||||
clientVersioningManager.getClientVisibility(txn,
|
||||
c.getId(), CLIENT_ID, MAJOR_VERSION);
|
||||
db.setGroupVisibility(txn, c.getId(), g.getId(), client);
|
||||
// Attach the contact ID to the group
|
||||
setContactId(txn, g.getId(), c.getId());
|
||||
|
||||
if (c.getHandshakePublicKey() == null) {
|
||||
sendHandshakePublicKey(txn, c);
|
||||
} else {
|
||||
LOG.info("Have pk for contact " + c.getAuthor().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void sendHandshakePublicKey(Transaction txn, Contact c)
|
||||
throws DbException {
|
||||
LOG.info("Sending our handshake public key to " + c.getAuthor().getName());
|
||||
Group group = getContactGroup(c);
|
||||
GroupId g = group.getId();
|
||||
if (!db.containsGroup(txn, g)) db.addGroup(txn, group);
|
||||
long timestamp = clock.currentTimeMillis();
|
||||
|
||||
BdfList bodyList = new BdfList();
|
||||
bodyList.add(handshakePublicKey);
|
||||
try {
|
||||
byte[] body = clientHelper.toByteArray(bodyList);
|
||||
Message m = clientHelper.createMessage(g, timestamp, body);
|
||||
|
||||
BdfDictionary meta = BdfDictionary.of(
|
||||
new BdfEntry(MSG_KEY_LOCAL, true),
|
||||
new BdfEntry(MSG_KEY_TIMESTAMP, timestamp)
|
||||
);
|
||||
clientHelper.addLocalMessage(txn, m, meta, true, false);
|
||||
} catch (FormatException e) {
|
||||
throw new DbException();
|
||||
}
|
||||
|
||||
// messageTracker.trackOutgoingMessage(txn, m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removingContact(Transaction txn, Contact c) throws DbException {
|
||||
db.removeGroup(txn, getContactGroup(c));
|
||||
}
|
||||
|
||||
private void setContactId(Transaction txn, GroupId g, ContactId c)
|
||||
throws DbException {
|
||||
BdfDictionary d = new BdfDictionary();
|
||||
d.put(GROUP_KEY_CONTACT_ID, c.getInt());
|
||||
try {
|
||||
clientHelper.mergeGroupMetadata(txn, g, d);
|
||||
} catch (FormatException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientVisibilityChanging(Transaction txn, Contact c,
|
||||
Group.Visibility v) throws DbException {
|
||||
// Apply the client's visibility to the contact group
|
||||
Group g = getContactGroup(c);
|
||||
db.setGroupVisibility(txn, c.getId(), g.getId(), v);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package org.briarproject.briar.handshakekeyexchange;
|
||||
|
||||
import org.briarproject.bramble.api.client.ClientHelper;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.data.MetadataEncoder;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.sync.validation.ValidationManager;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
||||
import org.briarproject.briar.api.conversation.ConversationManager;
|
||||
import org.briarproject.briar.api.handshakekeyexchange.HandshakeKeyExchangeManager;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
@Module
|
||||
public class HandshakeKeyExchangeModule {
|
||||
public static class EagerSingletons {
|
||||
@Inject
|
||||
HandshakeKeyExchangeManager handshakeKeyExchangeManager;
|
||||
|
||||
@Inject
|
||||
HandshakeKeyExchangeValidator handshakeKeyExchangeValidator;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
HandshakeKeyExchangeManager handshakeKeyExchangeManager(
|
||||
LifecycleManager lifecycleManager,
|
||||
ValidationManager validationManager,
|
||||
ContactManager contactManager,
|
||||
ClientVersioningManager clientVersioningManager,
|
||||
ConversationManager conversationManager,
|
||||
HandshakeKeyExchangeManagerImpl handshakeKeyExchangeManager) {
|
||||
|
||||
lifecycleManager.registerOpenDatabaseHook(handshakeKeyExchangeManager);
|
||||
validationManager
|
||||
.registerIncomingMessageHook(HandshakeKeyExchangeManager.CLIENT_ID,
|
||||
HandshakeKeyExchangeManager.MAJOR_VERSION, handshakeKeyExchangeManager);
|
||||
|
||||
contactManager.registerContactHook(handshakeKeyExchangeManager);
|
||||
clientVersioningManager.registerClient(HandshakeKeyExchangeManager.CLIENT_ID, HandshakeKeyExchangeManager.MAJOR_VERSION,
|
||||
HandshakeKeyExchangeManager.MINOR_VERSION, handshakeKeyExchangeManager);
|
||||
conversationManager.registerConversationClient(handshakeKeyExchangeManager);
|
||||
return handshakeKeyExchangeManager;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
HandshakeKeyExchangeValidator handshakeKeyExchangeValidator(
|
||||
ValidationManager validationManager,
|
||||
ClientHelper clientHelper,
|
||||
MetadataEncoder metadataEncoder,
|
||||
Clock clock) {
|
||||
HandshakeKeyExchangeValidator validator =
|
||||
new HandshakeKeyExchangeValidator(clientHelper, metadataEncoder, clock);
|
||||
validationManager.registerMessageValidator(HandshakeKeyExchangeManager.CLIENT_ID, HandshakeKeyExchangeManager.MAJOR_VERSION,
|
||||
validator);
|
||||
return validator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package org.briarproject.briar.handshakekeyexchange;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.client.BdfMessageContext;
|
||||
import org.briarproject.bramble.api.client.BdfMessageValidator;
|
||||
import org.briarproject.bramble.api.client.ClientHelper;
|
||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||
import org.briarproject.bramble.api.data.BdfEntry;
|
||||
import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.data.MetadataEncoder;
|
||||
import org.briarproject.bramble.api.sync.Group;
|
||||
import org.briarproject.bramble.api.sync.InvalidMessageException;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import static org.briarproject.briar.handshakekeyexchange.HandshakeKeyExchangeConstants.MSG_KEY_LOCAL;
|
||||
|
||||
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class HandshakeKeyExchangeValidator extends BdfMessageValidator {
|
||||
|
||||
@Inject
|
||||
protected HandshakeKeyExchangeValidator(
|
||||
ClientHelper clientHelper,
|
||||
MetadataEncoder metadataEncoder,
|
||||
Clock clock) {
|
||||
super(clientHelper, metadataEncoder, clock);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BdfMessageContext validateMessage(Message m, Group g,
|
||||
BdfList body) throws InvalidMessageException, FormatException {
|
||||
checkSize(body,1);
|
||||
BdfDictionary meta = BdfDictionary.of(
|
||||
new BdfEntry(MSG_KEY_LOCAL, false)
|
||||
);
|
||||
return new BdfMessageContext(meta);
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,11 @@ import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.Identity;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||
import org.briarproject.briar.api.socialbackup.BackupPayload;
|
||||
import org.briarproject.briar.api.socialbackup.ContactData;
|
||||
import org.briarproject.briar.api.socialbackup.MessageParser;
|
||||
import org.briarproject.briar.api.socialbackup.Shard;
|
||||
import org.briarproject.briar.api.socialbackup.SocialBackup;
|
||||
@@ -55,7 +57,7 @@ public class BackupPayloadDecoderImpl implements BackupPayloadDecoder {
|
||||
this.messageParser = messageParser;
|
||||
}
|
||||
|
||||
public org.briarproject.briar.api.socialbackup.SocialBackup decodeBackupPayload(
|
||||
public SocialBackup decodeBackupPayload(
|
||||
SecretKey secret,
|
||||
BackupPayload backupPayload)
|
||||
throws FormatException, GeneralSecurityException {
|
||||
@@ -98,13 +100,17 @@ public class BackupPayloadDecoderImpl implements BackupPayloadDecoder {
|
||||
PrivateKey handShakePrivateKey =
|
||||
new AgreementPrivateKey(bdfIdentity.getRaw(3));
|
||||
|
||||
Map<TransportId, TransportProperties> localProperties = clientHelper
|
||||
.parseAndValidateTransportPropertiesMap(
|
||||
bdfIdentity.getDictionary(4));
|
||||
LOG.info("Local transport properties parsed");
|
||||
|
||||
Long created = System.currentTimeMillis();
|
||||
|
||||
Identity identity = new Identity(localAuthor, handshakePublicKey,
|
||||
handShakePrivateKey, created);
|
||||
LOG.info("New identity created");
|
||||
|
||||
List<org.briarproject.briar.api.socialbackup.ContactData> contactDataList = new ArrayList();
|
||||
List<ContactData> contactDataList = new ArrayList();
|
||||
|
||||
for (int i = 0; i < bdfContactData.size(); i++) {
|
||||
BdfList bdfData = bdfContactData.getList(i);
|
||||
@@ -143,9 +149,9 @@ public class BackupPayloadDecoderImpl implements BackupPayloadDecoder {
|
||||
org.briarproject.briar.api.socialbackup.ContactData contactData =
|
||||
new org.briarproject.briar.api.socialbackup.ContactData(contact, properties, shard);
|
||||
contactDataList.add(contactData);
|
||||
LOG.info("Contact added");
|
||||
LOG.info("Contact fully parsed");
|
||||
}
|
||||
LOG.info("All contacts added");
|
||||
return new SocialBackup(identity, contactDataList, version);
|
||||
LOG.info("All contacts fully parsed");
|
||||
return new SocialBackup(identity, contactDataList, localProperties, version);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,17 @@ package org.briarproject.briar.socialbackup;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.identity.Identity;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||
import org.briarproject.briar.api.socialbackup.BackupPayload;
|
||||
import org.briarproject.briar.api.socialbackup.ContactData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@NotNullByDefault
|
||||
interface BackupPayloadEncoder {
|
||||
|
||||
BackupPayload encodeBackupPayload(SecretKey secret, Identity identity,
|
||||
List<ContactData> contactData, int version);
|
||||
List<ContactData> contactData, int version, Map<TransportId, TransportProperties> localTransportProperties);
|
||||
}
|
||||
|
||||
@@ -10,11 +10,15 @@ import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.identity.Identity;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||
import org.briarproject.briar.api.socialbackup.BackupPayload;
|
||||
import org.briarproject.briar.api.socialbackup.Shard;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
@@ -45,15 +49,26 @@ class BackupPayloadEncoderImpl implements BackupPayloadEncoder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.briarproject.briar.api.socialbackup.BackupPayload encodeBackupPayload(SecretKey secret,
|
||||
Identity identity, List<org.briarproject.briar.api.socialbackup.ContactData> contactData, int version) {
|
||||
public BackupPayload encodeBackupPayload(SecretKey secret,
|
||||
Identity identity,
|
||||
List<org.briarproject.briar.api.socialbackup.ContactData> contactData,
|
||||
int version,
|
||||
Map<TransportId, TransportProperties> localTransportProperties) {
|
||||
// Encode the local identity
|
||||
BdfList bdfIdentity = new BdfList();
|
||||
LocalAuthor localAuthor = identity.getLocalAuthor();
|
||||
bdfIdentity.add(clientHelper.toList(localAuthor));
|
||||
bdfIdentity.add(localAuthor.getPrivateKey().getEncoded());
|
||||
|
||||
// Add handshake keypair
|
||||
assert identity.getHandshakePublicKey() != null;
|
||||
bdfIdentity.add(identity.getHandshakePublicKey().getEncoded());
|
||||
assert identity.getHandshakePrivateKey() != null;
|
||||
bdfIdentity.add(identity.getHandshakePrivateKey().getEncoded());
|
||||
|
||||
// Add local transport properties
|
||||
bdfIdentity.add(clientHelper.toDictionary(localTransportProperties));
|
||||
|
||||
// Encode the contact data
|
||||
BdfList bdfContactData = new BdfList();
|
||||
for (org.briarproject.briar.api.socialbackup.ContactData cd : contactData) {
|
||||
@@ -84,10 +99,13 @@ class BackupPayloadEncoderImpl implements BackupPayloadEncoder {
|
||||
int encrypted = cipher.process(plaintext, 0, plaintext.length,
|
||||
ciphertext, 0);
|
||||
if (encrypted != ciphertext.length) throw new AssertionError();
|
||||
byte[] ciphertextWithNonce = new byte[ciphertext.length + nonce.length];
|
||||
byte[] ciphertextWithNonce =
|
||||
new byte[ciphertext.length + nonce.length];
|
||||
System.arraycopy(nonce, 0, ciphertextWithNonce, 0, nonce.length);
|
||||
System.arraycopy(ciphertext, 0, ciphertextWithNonce, nonce.length, ciphertext.length);
|
||||
return new org.briarproject.briar.api.socialbackup.BackupPayload(ciphertextWithNonce);
|
||||
System.arraycopy(ciphertext, 0, ciphertextWithNonce, nonce.length,
|
||||
ciphertext.length);
|
||||
return new org.briarproject.briar.api.socialbackup.BackupPayload(
|
||||
ciphertextWithNonce);
|
||||
} catch (FormatException | GeneralSecurityException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ import org.briarproject.briar.client.ConversationClientImpl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
@@ -66,7 +67,6 @@ import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
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;
|
||||
@@ -440,14 +440,25 @@ class SocialBackupManagerImpl extends ConversationClientImpl
|
||||
int version)
|
||||
throws DbException {
|
||||
Identity identity = identityManager.getIdentity(txn);
|
||||
|
||||
// Add local transport properties
|
||||
Map<TransportId, TransportProperties> localProps =
|
||||
transportPropertyManager.getLocalProperties(txn);
|
||||
Map<TransportId, TransportProperties> filteredLocalProps =
|
||||
new HashMap<>();
|
||||
if (localProps.get(TorConstants.ID) != null) {
|
||||
filteredLocalProps
|
||||
.put(TorConstants.ID, localProps.get(TorConstants.ID));
|
||||
}
|
||||
|
||||
return backupPayloadEncoder.encodeBackupPayload(secret, identity,
|
||||
contactData, version);
|
||||
contactData, version, filteredLocalProps);
|
||||
}
|
||||
|
||||
private List<ContactData> loadContactData(Transaction txn)
|
||||
throws DbException {
|
||||
Collection<Contact> contacts = contactManager.getContacts(txn);
|
||||
List<org.briarproject.briar.api.socialbackup.ContactData> contactData =
|
||||
List<ContactData> contactData =
|
||||
new ArrayList<>();
|
||||
for (Contact c : contacts) {
|
||||
// Skip contacts that are in the process of being removed
|
||||
@@ -456,6 +467,10 @@ class SocialBackupManagerImpl extends ConversationClientImpl
|
||||
Map<TransportId, TransportProperties> props =
|
||||
getTransportProperties(txn, c.getId());
|
||||
Shard shard = getRemoteShard(txn, contactGroup.getId());
|
||||
if (c.getHandshakePublicKey() == null) {
|
||||
System.out.println(
|
||||
"Warning - adding contact with no handshake public key");
|
||||
}
|
||||
contactData
|
||||
.add(new org.briarproject.briar.api.socialbackup.ContactData(
|
||||
c, props, shard));
|
||||
@@ -466,9 +481,14 @@ class SocialBackupManagerImpl extends ConversationClientImpl
|
||||
private Map<TransportId, TransportProperties> getTransportProperties(
|
||||
Transaction txn, ContactId c) throws DbException {
|
||||
// TODO: Include filtered properties for other transports
|
||||
TransportProperties p = transportPropertyManager
|
||||
.getRemoteProperties(txn, c, TorConstants.ID);
|
||||
return singletonMap(TorConstants.ID, p);
|
||||
TransportId ids[] = {TorConstants.ID};
|
||||
// {TorConstants.ID, LanTcpConstants.ID, BluetoothConstants.ID};
|
||||
Map<TransportId, TransportProperties> props = new HashMap();
|
||||
for (TransportId id : ids) {
|
||||
props.put(id, transportPropertyManager
|
||||
.getRemoteProperties(txn, c, id));
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
private void sendShardMessage(Transaction txn, Contact custodian,
|
||||
@@ -562,7 +582,7 @@ class SocialBackupManagerImpl extends ConversationClientImpl
|
||||
db.deleteMessageMetadata(txn, prevId);
|
||||
}
|
||||
sendBackupMessage(txn, custodian, newVersion, payload);
|
||||
} catch (NoSuchContactException|NoSuchGroupException e){
|
||||
} catch (NoSuchContactException | NoSuchGroupException e) {
|
||||
// The custodian is no longer a contact - continue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package org.briarproject.briar.socialbackup.recovery;
|
||||
|
||||
import org.briarproject.bramble.api.FormatException;
|
||||
import org.briarproject.bramble.api.client.ClientHelper;
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
@@ -9,9 +11,15 @@ import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
import org.briarproject.briar.api.socialbackup.BackupPayload;
|
||||
import org.briarproject.briar.api.socialbackup.ContactData;
|
||||
import org.briarproject.briar.api.socialbackup.DarkCrystal;
|
||||
import org.briarproject.briar.api.socialbackup.MessageEncoder;
|
||||
import org.briarproject.briar.api.socialbackup.MessageParser;
|
||||
import org.briarproject.briar.api.socialbackup.ReturnShardPayload;
|
||||
import org.briarproject.briar.api.socialbackup.Shard;
|
||||
import org.briarproject.briar.api.socialbackup.SocialBackup;
|
||||
@@ -21,6 +29,9 @@ import org.briarproject.briar.socialbackup.BackupPayloadDecoder;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -29,14 +40,18 @@ import javax.inject.Inject;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
|
||||
public class RestoreAccountImpl implements RestoreAccount {
|
||||
private final ArrayList<ReturnShardPayload> recoveredShards = new ArrayList<>();
|
||||
private final Set<ReturnShardPayload> recoveredShards = new HashSet<>();
|
||||
private final DarkCrystal darkCrystal;
|
||||
private final Executor ioExecutor;
|
||||
private final DatabaseComponent db;
|
||||
private final ContactManager contactManager;
|
||||
private final MessageEncoder messageEncoder;
|
||||
private final MessageParser messageParser;
|
||||
private final TransportPropertyManager transportPropertyManager;
|
||||
private final LifecycleManager lifecycleManager;
|
||||
private SecretKey secretKey;
|
||||
private final BackupPayloadDecoder backupPayloadDecoder;
|
||||
private final ClientHelper clientHelper;
|
||||
private SocialBackup socialBackup;
|
||||
private byte[] secretId;
|
||||
|
||||
@@ -48,20 +63,29 @@ public class RestoreAccountImpl implements RestoreAccount {
|
||||
BackupPayloadDecoder backupPayloadDecoder, DatabaseComponent db,
|
||||
@IoExecutor Executor ioExecutor,
|
||||
ContactManager contactManager,
|
||||
LifecycleManager lifecycleManager) {
|
||||
LifecycleManager lifecycleManager,
|
||||
TransportPropertyManager transportPropertyManager,
|
||||
MessageEncoder messageEncoder,
|
||||
MessageParser messageParser,
|
||||
ClientHelper clientHelper) {
|
||||
this.darkCrystal = darkCrystal;
|
||||
this.backupPayloadDecoder = backupPayloadDecoder;
|
||||
this.db = db;
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.lifecycleManager = lifecycleManager;
|
||||
this.contactManager = contactManager;
|
||||
this.transportPropertyManager = transportPropertyManager;
|
||||
this.messageEncoder = messageEncoder;
|
||||
this.messageParser = messageParser;
|
||||
this.clientHelper = clientHelper;
|
||||
}
|
||||
|
||||
public int getNumberOfShards() {
|
||||
return recoveredShards.size();
|
||||
}
|
||||
|
||||
public AddReturnShardPayloadResult addReturnShardPayload(ReturnShardPayload toAdd) {
|
||||
public AddReturnShardPayloadResult addReturnShardPayload(
|
||||
ReturnShardPayload toAdd) {
|
||||
AddReturnShardPayloadResult result = AddReturnShardPayloadResult.OK;
|
||||
// TODO figure out how to actually use a hash set for these objects
|
||||
for (ReturnShardPayload returnShardPayload : recoveredShards) {
|
||||
@@ -75,7 +99,8 @@ public class RestoreAccountImpl implements RestoreAccount {
|
||||
return AddReturnShardPayloadResult.MISMATCH;
|
||||
}
|
||||
recoveredShards.add(toAdd);
|
||||
return AddReturnShardPayloadResult.OK;
|
||||
return canRecover() ? AddReturnShardPayloadResult.RECOVERED :
|
||||
AddReturnShardPayloadResult.OK;
|
||||
}
|
||||
|
||||
public boolean canRecover() {
|
||||
@@ -115,10 +140,7 @@ public class RestoreAccountImpl implements RestoreAccount {
|
||||
return socialBackup;
|
||||
}
|
||||
|
||||
public void addContactsToDb() throws DbException {
|
||||
if (socialBackup == null) throw new DbException();
|
||||
AuthorId localAuthorId = socialBackup.getIdentity().getId();
|
||||
|
||||
public void restoreAccountWhenDatabaseReady() throws DbException {
|
||||
ioExecutor.execute(() -> {
|
||||
try {
|
||||
lifecycleManager.waitForDatabase();
|
||||
@@ -126,19 +148,80 @@ public class RestoreAccountImpl implements RestoreAccount {
|
||||
LOG.warning("Interrupted when waiting for database");
|
||||
}
|
||||
try {
|
||||
db.transaction(false, txn -> {
|
||||
for (ContactData contactData : socialBackup.getContacts()) {
|
||||
Contact c = contactData.getContact();
|
||||
LOG.info("Adding contact " + c.getAuthor().getName() + " " + c.getAlias());
|
||||
contactManager.addContact(txn, c.getAuthor(), localAuthorId,
|
||||
c.getHandshakePublicKey(), c.isVerified());
|
||||
}
|
||||
});
|
||||
addLocalTransportProperties();
|
||||
addContactsToDb();
|
||||
} catch (DbException e) {
|
||||
LOG.warning("Error adding contacts to database");
|
||||
LOG.warning(e.getMessage());
|
||||
LOG.warning("Error when processing backup");
|
||||
e.printStackTrace();
|
||||
}
|
||||
LOG.info("Added all contacts");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void addContactsToDb() throws DbException {
|
||||
if (socialBackup == null) throw new DbException();
|
||||
AuthorId localAuthorId = socialBackup.getIdentity().getId();
|
||||
|
||||
try {
|
||||
db.transaction(false, txn -> {
|
||||
for (ContactData contactData : socialBackup.getContacts()) {
|
||||
Contact c = contactData.getContact();
|
||||
LOG.info("Adding contact " + c.getAuthor().getName() +
|
||||
" " + c.getAlias());
|
||||
if (c.getHandshakePublicKey() == null) {
|
||||
LOG.warning(
|
||||
"Warning: contact has no handshake public key");
|
||||
}
|
||||
ContactId contactId = contactManager
|
||||
.addContact(txn, c.getAuthor(), localAuthorId,
|
||||
c.getHandshakePublicKey(),
|
||||
c.isVerified());
|
||||
transportPropertyManager
|
||||
.addRemoteProperties(txn, contactId,
|
||||
contactData.getProperties());
|
||||
}
|
||||
});
|
||||
} catch (DbException e) {
|
||||
LOG.warning("Error adding contacts to database");
|
||||
LOG.warning(e.getMessage());
|
||||
} catch (GeneralSecurityException e) {
|
||||
LOG.warning("Error adding handshake key");
|
||||
LOG.warning(e.getMessage());
|
||||
}
|
||||
LOG.info("Added all contacts");
|
||||
}
|
||||
|
||||
private void addLocalTransportProperties()
|
||||
throws DbException {
|
||||
LOG.info("Adding local transport properties");
|
||||
for (Map.Entry<TransportId, TransportProperties> propertiesEntry : socialBackup
|
||||
.getLocalTransportProperties().entrySet()) {
|
||||
LOG.info("Adding transport property " +
|
||||
propertiesEntry.getKey().getString());
|
||||
transportPropertyManager
|
||||
.mergeLocalProperties(propertiesEntry.getKey(),
|
||||
propertiesEntry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> getEncodedShards() {
|
||||
Set<String> s = new HashSet();
|
||||
for (ReturnShardPayload r : recoveredShards) {
|
||||
s.add(StringUtils
|
||||
.toHexString(messageEncoder.encodeReturnShardPayload(r)));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public void restoreFromPrevious(Set<String> previousShards) {
|
||||
for (String s : previousShards) {
|
||||
try {
|
||||
addReturnShardPayload(messageParser.parseReturnShardPayload(
|
||||
clientHelper.toList(StringUtils.fromHexString(s))));
|
||||
} catch (FormatException e) {
|
||||
LOG.warning("Error parsing shard from previous session");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ buildscript {
|
||||
classpath files('libs/gradle-witness.jar')
|
||||
}
|
||||
|
||||
// ext.dagger_version = "2.33"
|
||||
ext.junit_version = "4.12"
|
||||
ext.jmock_version = '2.12.0'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user