From f67d2f0157f4e2a80cfd2a22cb14153d93edc0a2 Mon Sep 17 00:00:00 2001 From: ameba23 Date: Fri, 25 Jun 2021 13:03:45 +0200 Subject: [PATCH] Include local tor properties in backup and check for remote handshake public keys --- .../recover/RestoreAccountActivity.java | 6 +- .../recover/RestoreAccountViewModel.java | 7 +- .../briar/api/socialbackup/SocialBackup.java | 11 ++- .../socialbackup/recovery/RestoreAccount.java | 6 +- .../BackupPayloadDecoderImpl.java | 18 +++-- .../socialbackup/BackupPayloadEncoder.java | 5 +- .../BackupPayloadEncoderImpl.java | 28 +++++-- .../socialbackup/SocialBackupManagerImpl.java | 21 ++++- .../recovery/RestoreAccountImpl.java | 77 ++++++++++++++----- 9 files changed, 137 insertions(+), 42 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/RestoreAccountActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/RestoreAccountActivity.java index 2c9a3fefe..b8a97e7b8 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/RestoreAccountActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/RestoreAccountActivity.java @@ -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(); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/RestoreAccountViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/RestoreAccountViewModel.java index a4fbc4cdf..a11ac2353 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/RestoreAccountViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/socialbackup/recover/RestoreAccountViewModel.java @@ -114,16 +114,19 @@ 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 diff --git a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/SocialBackup.java b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/SocialBackup.java index 1be5a0822..86ea4847b 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/SocialBackup.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/SocialBackup.java @@ -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 contacts; + private Map localTransportProperties; private int version; - public SocialBackup (Identity identity, List contacts, int version) { + public SocialBackup (Identity identity, List contacts, Map 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 getLocalTransportProperties() { + return localTransportProperties; + } + public int getVersion() { return version; } diff --git a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/RestoreAccount.java b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/RestoreAccount.java index 571ae5eac..2edc812b7 100644 --- a/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/RestoreAccount.java +++ b/briar-api/src/main/java/org/briarproject/briar/api/socialbackup/recovery/RestoreAccount.java @@ -29,7 +29,11 @@ public interface RestoreAccount { SocialBackup getSocialBackup(); - void addContactsToDb() throws DbException; +// void addContactsToDb() throws DbException; void restoreFromPrevious(Set previousShards); + + void restoreAccountWhenDatabaseReady() throws DbException; + +// void addLocalTransportProperties() throws DbException; } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadDecoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadDecoderImpl.java index 4171d8154..20404372a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadDecoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadDecoderImpl.java @@ -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 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 contactDataList = new ArrayList(); + List 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); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoder.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoder.java index ed8e852b2..ca5274bd6 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoder.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoder.java @@ -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, int version); + List contactData, int version, Map localTransportProperties); } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoderImpl.java index 7e867f697..ba1df879f 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoderImpl.java @@ -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 contactData, int version) { + public BackupPayload encodeBackupPayload(SecretKey secret, + Identity identity, + List contactData, + int version, + Map 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); } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupManagerImpl.java index e7ec723d5..5e2198772 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupManagerImpl.java @@ -29,7 +29,6 @@ import org.briarproject.bramble.api.plugin.BluetoothConstants; import org.briarproject.bramble.api.plugin.LanTcpConstants; import org.briarproject.bramble.api.plugin.TorConstants; import org.briarproject.bramble.api.plugin.TransportId; -import org.briarproject.bramble.api.plugin.WanTcpConstants; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportPropertyManager; import org.briarproject.bramble.api.sync.Group; @@ -442,14 +441,23 @@ class SocialBackupManagerImpl extends ConversationClientImpl int version) throws DbException { Identity identity = identityManager.getIdentity(txn); + + // Add local transport properties + Map localProps = + transportPropertyManager.getLocalProperties(txn); + Map filteredLocalProps = + new HashMap<>(); + filteredLocalProps + .put(TorConstants.ID, localProps.get(TorConstants.ID)); + return backupPayloadEncoder.encodeBackupPayload(secret, identity, - contactData, version); + contactData, version, filteredLocalProps); } private List loadContactData(Transaction txn) throws DbException { Collection contacts = contactManager.getContacts(txn); - List contactData = + List contactData = new ArrayList<>(); for (Contact c : contacts) { // Skip contacts that are in the process of being removed @@ -458,6 +466,10 @@ class SocialBackupManagerImpl extends ConversationClientImpl Map 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)); @@ -468,7 +480,8 @@ class SocialBackupManagerImpl extends ConversationClientImpl private Map getTransportProperties( Transaction txn, ContactId c) throws DbException { // TODO: Include filtered properties for other transports - TransportId ids[] = { TorConstants.ID, LanTcpConstants.ID, BluetoothConstants.ID }; + TransportId ids[] = + {TorConstants.ID, LanTcpConstants.ID, BluetoothConstants.ID}; Map props = new HashMap(); for (TransportId id : ids) { props.put(id, transportPropertyManager diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/RestoreAccountImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/RestoreAccountImpl.java index c3a56adbd..c8611753b 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/RestoreAccountImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/recovery/RestoreAccountImpl.java @@ -11,6 +11,8 @@ 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.briar.api.socialbackup.BackupPayload; import org.briarproject.briar.api.socialbackup.ContactData; @@ -27,6 +29,7 @@ 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; @@ -80,7 +83,8 @@ public class RestoreAccountImpl implements RestoreAccount { 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) { @@ -94,7 +98,8 @@ public class RestoreAccountImpl implements RestoreAccount { return AddReturnShardPayloadResult.MISMATCH; } recoveredShards.add(toAdd); - return canRecover() ? AddReturnShardPayloadResult.RECOVERED : AddReturnShardPayloadResult.OK; + return canRecover() ? AddReturnShardPayloadResult.RECOVERED : + AddReturnShardPayloadResult.OK; } public boolean canRecover() { @@ -134,10 +139,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(); @@ -145,24 +147,58 @@ 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()); - ContactId contactId = contactManager.addContact(txn, c.getAuthor(), localAuthorId, - c.getHandshakePublicKey(), c.isVerified()); - transportPropertyManager.addRemoteProperties(txn, contactId, - contactData.getProperties()); - } - }); + 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()); + } + LOG.info("Added all contacts"); + } + + private void addLocalTransportProperties() + throws DbException { + LOG.info("Adding local transport properties"); + for (Map.Entry propertiesEntry : socialBackup + .getLocalTransportProperties().entrySet()) { + LOG.info("Adding transport property " + + propertiesEntry.getKey().getString()); + transportPropertyManager + .mergeLocalProperties(propertiesEntry.getKey(), + propertiesEntry.getValue()); + } + } + public Set getEncodedShards() { Set s = new HashSet(); for (ReturnShardPayload r : recoveredShards) { @@ -174,7 +210,8 @@ public class RestoreAccountImpl implements RestoreAccount { public void restoreFromPrevious(Set previousShards) { for (String s : previousShards) { try { - addReturnShardPayload(messageParser.parseReturnShardPayload(clientHelper.toList(s.getBytes()))); + addReturnShardPayload(messageParser.parseReturnShardPayload( + clientHelper.toList(s.getBytes()))); } catch (FormatException e) { e.printStackTrace(); }