Include local tor properties in backup and check for remote handshake public keys

This commit is contained in:
ameba23
2021-06-25 13:03:45 +02:00
parent ef05ecc342
commit f67d2f0157
9 changed files with 137 additions and 42 deletions

View File

@@ -52,9 +52,11 @@ public class RestoreAccountActivity extends BaseActivity
showInitialFragment(RestoreAccountSetPasswordFragment.newInstance()); showInitialFragment(RestoreAccountSetPasswordFragment.newInstance());
} else if (state == State.DOZE) { } else if (state == State.DOZE) {
showDozeFragment(); showDozeFragment();
} else if (state == State.CREATED || state == State.FAILED) { } else if (state == State.CREATED) {
// TODO: Show an error if failed
showApp(); showApp();
} else { // FAILED
// TODO: Show an error if failed
finish();
} }
} }

View File

@@ -114,16 +114,19 @@ class RestoreAccountViewModel extends AndroidViewModel {
if (socialBackup == null) { if (socialBackup == null) {
LOG.warning("Cannot retrieve social backup"); LOG.warning("Cannot retrieve social backup");
state.postEvent(State.FAILED); state.postEvent(State.FAILED);
return;
} }
Identity identity = socialBackup.getIdentity(); Identity identity = socialBackup.getIdentity();
ioExecutor.execute(() -> { ioExecutor.execute(() -> {
if (accountManager.restoreAccount(identity, password)) { if (accountManager.restoreAccount(identity, password)) {
LOG.info("Restored account"); LOG.info("Restored account");
try { try {
restoreAccount.addContactsToDb(); restoreAccount.restoreAccountWhenDatabaseReady();
} catch (DbException e) { } catch (DbException e) {
LOG.warning("Cannot retrieve social backup"); LOG.warning("Failure processing social backup");
e.printStackTrace();
state.postEvent(State.FAILED); state.postEvent(State.FAILED);
return;
} }
// Remove partial recovery from shared preferences // Remove partial recovery from shared preferences

View File

@@ -1,17 +1,22 @@
package org.briarproject.briar.api.socialbackup; package org.briarproject.briar.api.socialbackup;
import org.briarproject.bramble.api.identity.Identity; 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.List;
import java.util.Map;
public class SocialBackup { public class SocialBackup {
private Identity identity; private Identity identity;
private List<ContactData> contacts; private List<ContactData> contacts;
private Map<TransportId, TransportProperties> localTransportProperties;
private int version; 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.identity = identity;
this.contacts = contacts; this.contacts = contacts;
this.localTransportProperties = localTransportProperties;
this.version = version; this.version = version;
} }
@@ -23,6 +28,10 @@ public class SocialBackup {
return contacts; return contacts;
} }
public Map<TransportId, TransportProperties> getLocalTransportProperties() {
return localTransportProperties;
}
public int getVersion() { public int getVersion() {
return version; return version;
} }

View File

@@ -29,7 +29,11 @@ public interface RestoreAccount {
SocialBackup getSocialBackup(); SocialBackup getSocialBackup();
void addContactsToDb() throws DbException; // void addContactsToDb() throws DbException;
void restoreFromPrevious(Set<String> previousShards); void restoreFromPrevious(Set<String> previousShards);
void restoreAccountWhenDatabaseReady() throws DbException;
// void addLocalTransportProperties() throws DbException;
} }

View File

@@ -15,9 +15,11 @@ import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.Identity; import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.identity.LocalAuthor; 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.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.briar.api.socialbackup.BackupPayload; 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.MessageParser;
import org.briarproject.briar.api.socialbackup.Shard; import org.briarproject.briar.api.socialbackup.Shard;
import org.briarproject.briar.api.socialbackup.SocialBackup; import org.briarproject.briar.api.socialbackup.SocialBackup;
@@ -55,7 +57,7 @@ public class BackupPayloadDecoderImpl implements BackupPayloadDecoder {
this.messageParser = messageParser; this.messageParser = messageParser;
} }
public org.briarproject.briar.api.socialbackup.SocialBackup decodeBackupPayload( public SocialBackup decodeBackupPayload(
SecretKey secret, SecretKey secret,
BackupPayload backupPayload) BackupPayload backupPayload)
throws FormatException, GeneralSecurityException { throws FormatException, GeneralSecurityException {
@@ -98,13 +100,17 @@ public class BackupPayloadDecoderImpl implements BackupPayloadDecoder {
PrivateKey handShakePrivateKey = PrivateKey handShakePrivateKey =
new AgreementPrivateKey(bdfIdentity.getRaw(3)); new AgreementPrivateKey(bdfIdentity.getRaw(3));
Map<TransportId, TransportProperties> localProperties = clientHelper
.parseAndValidateTransportPropertiesMap(
bdfIdentity.getDictionary(4));
LOG.info("Local transport properties parsed");
Long created = System.currentTimeMillis(); Long created = System.currentTimeMillis();
Identity identity = new Identity(localAuthor, handshakePublicKey, Identity identity = new Identity(localAuthor, handshakePublicKey,
handShakePrivateKey, created); 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++) { for (int i = 0; i < bdfContactData.size(); i++) {
BdfList bdfData = bdfContactData.getList(i); BdfList bdfData = bdfContactData.getList(i);
@@ -143,9 +149,9 @@ public class BackupPayloadDecoderImpl implements BackupPayloadDecoder {
org.briarproject.briar.api.socialbackup.ContactData contactData = org.briarproject.briar.api.socialbackup.ContactData contactData =
new org.briarproject.briar.api.socialbackup.ContactData(contact, properties, shard); new org.briarproject.briar.api.socialbackup.ContactData(contact, properties, shard);
contactDataList.add(contactData); contactDataList.add(contactData);
LOG.info("Contact added"); LOG.info("Contact fully parsed");
} }
LOG.info("All contacts added"); LOG.info("All contacts fully parsed");
return new SocialBackup(identity, contactDataList, version); return new SocialBackup(identity, contactDataList, localProperties, version);
} }
} }

View File

@@ -3,14 +3,17 @@ package org.briarproject.briar.socialbackup;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.identity.Identity; import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; 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.BackupPayload;
import org.briarproject.briar.api.socialbackup.ContactData; import org.briarproject.briar.api.socialbackup.ContactData;
import java.util.List; import java.util.List;
import java.util.Map;
@NotNullByDefault @NotNullByDefault
interface BackupPayloadEncoder { interface BackupPayloadEncoder {
BackupPayload encodeBackupPayload(SecretKey secret, Identity identity, BackupPayload encodeBackupPayload(SecretKey secret, Identity identity,
List<ContactData> contactData, int version); List<ContactData> contactData, int version, Map<TransportId, TransportProperties> localTransportProperties);
} }

View File

@@ -10,11 +10,15 @@ import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.identity.Identity; import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; 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 org.briarproject.briar.api.socialbackup.Shard;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; import javax.inject.Inject;
@@ -45,15 +49,26 @@ class BackupPayloadEncoderImpl implements BackupPayloadEncoder {
} }
@Override @Override
public org.briarproject.briar.api.socialbackup.BackupPayload encodeBackupPayload(SecretKey secret, public BackupPayload encodeBackupPayload(SecretKey secret,
Identity identity, List<org.briarproject.briar.api.socialbackup.ContactData> contactData, int version) { Identity identity,
List<org.briarproject.briar.api.socialbackup.ContactData> contactData,
int version,
Map<TransportId, TransportProperties> localTransportProperties) {
// Encode the local identity // Encode the local identity
BdfList bdfIdentity = new BdfList(); BdfList bdfIdentity = new BdfList();
LocalAuthor localAuthor = identity.getLocalAuthor(); LocalAuthor localAuthor = identity.getLocalAuthor();
bdfIdentity.add(clientHelper.toList(localAuthor)); bdfIdentity.add(clientHelper.toList(localAuthor));
bdfIdentity.add(localAuthor.getPrivateKey().getEncoded()); bdfIdentity.add(localAuthor.getPrivateKey().getEncoded());
// Add handshake keypair
assert identity.getHandshakePublicKey() != null;
bdfIdentity.add(identity.getHandshakePublicKey().getEncoded()); bdfIdentity.add(identity.getHandshakePublicKey().getEncoded());
assert identity.getHandshakePrivateKey() != null;
bdfIdentity.add(identity.getHandshakePrivateKey().getEncoded()); bdfIdentity.add(identity.getHandshakePrivateKey().getEncoded());
// Add local transport properties
bdfIdentity.add(clientHelper.toDictionary(localTransportProperties));
// Encode the contact data // Encode the contact data
BdfList bdfContactData = new BdfList(); BdfList bdfContactData = new BdfList();
for (org.briarproject.briar.api.socialbackup.ContactData cd : contactData) { 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, int encrypted = cipher.process(plaintext, 0, plaintext.length,
ciphertext, 0); ciphertext, 0);
if (encrypted != ciphertext.length) throw new AssertionError(); 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(nonce, 0, ciphertextWithNonce, 0, nonce.length);
System.arraycopy(ciphertext, 0, ciphertextWithNonce, nonce.length, ciphertext.length); System.arraycopy(ciphertext, 0, ciphertextWithNonce, nonce.length,
return new org.briarproject.briar.api.socialbackup.BackupPayload(ciphertextWithNonce); ciphertext.length);
return new org.briarproject.briar.api.socialbackup.BackupPayload(
ciphertextWithNonce);
} catch (FormatException | GeneralSecurityException e) { } catch (FormatException | GeneralSecurityException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }

View File

@@ -29,7 +29,6 @@ import org.briarproject.bramble.api.plugin.BluetoothConstants;
import org.briarproject.bramble.api.plugin.LanTcpConstants; import org.briarproject.bramble.api.plugin.LanTcpConstants;
import org.briarproject.bramble.api.plugin.TorConstants; import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.bramble.api.plugin.TransportId; 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.TransportProperties;
import org.briarproject.bramble.api.properties.TransportPropertyManager; import org.briarproject.bramble.api.properties.TransportPropertyManager;
import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.Group;
@@ -442,14 +441,23 @@ class SocialBackupManagerImpl extends ConversationClientImpl
int version) int version)
throws DbException { throws DbException {
Identity identity = identityManager.getIdentity(txn); Identity identity = identityManager.getIdentity(txn);
// Add local transport properties
Map<TransportId, TransportProperties> localProps =
transportPropertyManager.getLocalProperties(txn);
Map<TransportId, TransportProperties> filteredLocalProps =
new HashMap<>();
filteredLocalProps
.put(TorConstants.ID, localProps.get(TorConstants.ID));
return backupPayloadEncoder.encodeBackupPayload(secret, identity, return backupPayloadEncoder.encodeBackupPayload(secret, identity,
contactData, version); contactData, version, filteredLocalProps);
} }
private List<ContactData> loadContactData(Transaction txn) private List<ContactData> loadContactData(Transaction txn)
throws DbException { throws DbException {
Collection<Contact> contacts = contactManager.getContacts(txn); Collection<Contact> contacts = contactManager.getContacts(txn);
List<org.briarproject.briar.api.socialbackup.ContactData> contactData = List<ContactData> contactData =
new ArrayList<>(); new ArrayList<>();
for (Contact c : contacts) { for (Contact c : contacts) {
// Skip contacts that are in the process of being removed // Skip contacts that are in the process of being removed
@@ -458,6 +466,10 @@ class SocialBackupManagerImpl extends ConversationClientImpl
Map<TransportId, TransportProperties> props = Map<TransportId, TransportProperties> props =
getTransportProperties(txn, c.getId()); getTransportProperties(txn, c.getId());
Shard shard = getRemoteShard(txn, contactGroup.getId()); Shard shard = getRemoteShard(txn, contactGroup.getId());
if (c.getHandshakePublicKey() == null) {
System.out.println(
"Warning - adding contact with no handshake public key");
}
contactData contactData
.add(new org.briarproject.briar.api.socialbackup.ContactData( .add(new org.briarproject.briar.api.socialbackup.ContactData(
c, props, shard)); c, props, shard));
@@ -468,7 +480,8 @@ class SocialBackupManagerImpl extends ConversationClientImpl
private Map<TransportId, TransportProperties> getTransportProperties( private Map<TransportId, TransportProperties> getTransportProperties(
Transaction txn, ContactId c) throws DbException { Transaction txn, ContactId c) throws DbException {
// TODO: Include filtered properties for other transports // TODO: Include filtered properties for other transports
TransportId ids[] = { TorConstants.ID, LanTcpConstants.ID, BluetoothConstants.ID }; TransportId ids[] =
{TorConstants.ID, LanTcpConstants.ID, BluetoothConstants.ID};
Map<TransportId, TransportProperties> props = new HashMap(); Map<TransportId, TransportProperties> props = new HashMap();
for (TransportId id : ids) { for (TransportId id : ids) {
props.put(id, transportPropertyManager props.put(id, transportPropertyManager

View File

@@ -11,6 +11,8 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; 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.api.properties.TransportPropertyManager;
import org.briarproject.briar.api.socialbackup.BackupPayload; import org.briarproject.briar.api.socialbackup.BackupPayload;
import org.briarproject.briar.api.socialbackup.ContactData; import org.briarproject.briar.api.socialbackup.ContactData;
@@ -27,6 +29,7 @@ import java.security.GeneralSecurityException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -80,7 +83,8 @@ public class RestoreAccountImpl implements RestoreAccount {
return recoveredShards.size(); return recoveredShards.size();
} }
public AddReturnShardPayloadResult addReturnShardPayload(ReturnShardPayload toAdd) { public AddReturnShardPayloadResult addReturnShardPayload(
ReturnShardPayload toAdd) {
AddReturnShardPayloadResult result = AddReturnShardPayloadResult.OK; AddReturnShardPayloadResult result = AddReturnShardPayloadResult.OK;
// TODO figure out how to actually use a hash set for these objects // TODO figure out how to actually use a hash set for these objects
for (ReturnShardPayload returnShardPayload : recoveredShards) { for (ReturnShardPayload returnShardPayload : recoveredShards) {
@@ -94,7 +98,8 @@ public class RestoreAccountImpl implements RestoreAccount {
return AddReturnShardPayloadResult.MISMATCH; return AddReturnShardPayloadResult.MISMATCH;
} }
recoveredShards.add(toAdd); recoveredShards.add(toAdd);
return canRecover() ? AddReturnShardPayloadResult.RECOVERED : AddReturnShardPayloadResult.OK; return canRecover() ? AddReturnShardPayloadResult.RECOVERED :
AddReturnShardPayloadResult.OK;
} }
public boolean canRecover() { public boolean canRecover() {
@@ -134,10 +139,7 @@ public class RestoreAccountImpl implements RestoreAccount {
return socialBackup; return socialBackup;
} }
public void addContactsToDb() throws DbException { public void restoreAccountWhenDatabaseReady() throws DbException {
if (socialBackup == null) throw new DbException();
AuthorId localAuthorId = socialBackup.getIdentity().getId();
ioExecutor.execute(() -> { ioExecutor.execute(() -> {
try { try {
lifecycleManager.waitForDatabase(); lifecycleManager.waitForDatabase();
@@ -145,24 +147,58 @@ public class RestoreAccountImpl implements RestoreAccount {
LOG.warning("Interrupted when waiting for database"); LOG.warning("Interrupted when waiting for database");
} }
try { try {
db.transaction(false, txn -> { addLocalTransportProperties();
for (ContactData contactData : socialBackup.getContacts()) { addContactsToDb();
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());
}
});
} catch (DbException e) { } catch (DbException e) {
LOG.warning("Error adding contacts to database"); LOG.warning("Error when processing backup");
LOG.warning(e.getMessage()); 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<TransportId, TransportProperties> propertiesEntry : socialBackup
.getLocalTransportProperties().entrySet()) {
LOG.info("Adding transport property " +
propertiesEntry.getKey().getString());
transportPropertyManager
.mergeLocalProperties(propertiesEntry.getKey(),
propertiesEntry.getValue());
}
}
public Set<String> getEncodedShards() { public Set<String> getEncodedShards() {
Set<String> s = new HashSet(); Set<String> s = new HashSet();
for (ReturnShardPayload r : recoveredShards) { for (ReturnShardPayload r : recoveredShards) {
@@ -174,7 +210,8 @@ public class RestoreAccountImpl implements RestoreAccount {
public void restoreFromPrevious(Set<String> previousShards) { public void restoreFromPrevious(Set<String> previousShards) {
for (String s : previousShards) { for (String s : previousShards) {
try { try {
addReturnShardPayload(messageParser.parseReturnShardPayload(clientHelper.toList(s.getBytes()))); addReturnShardPayload(messageParser.parseReturnShardPayload(
clientHelper.toList(s.getBytes())));
} catch (FormatException e) { } catch (FormatException e) {
e.printStackTrace(); e.printStackTrace();
} }