From d40bb2d9eebc3321bf8da6bb81420ad720261855 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Thu, 29 Jul 2021 17:45:20 -0400 Subject: [PATCH] Clear all sender key knowledge for a device after a 409/410. --- .../storage/SignalProtocolStoreImpl.java | 6 +-- .../crypto/storage/SignalSenderKeyStore.java | 4 +- .../database/SenderKeySharedDatabase.java | 21 +++++++++- .../securesms/messages/GroupSendUtil.java | 2 +- .../api/SignalServiceMessageSender.java | 42 ++++++++++--------- .../api/SignalServiceSenderKeyStore.java | 4 +- 6 files changed, 50 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalProtocolStoreImpl.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalProtocolStoreImpl.java index 5276f5d643..bd8302363a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalProtocolStoreImpl.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalProtocolStoreImpl.java @@ -12,8 +12,6 @@ import org.whispersystems.libsignal.state.IdentityKeyStore; import org.whispersystems.libsignal.state.PreKeyRecord; import org.whispersystems.libsignal.state.PreKeyStore; import org.whispersystems.libsignal.state.SessionRecord; -import org.whispersystems.libsignal.state.SessionStore; -import org.whispersystems.libsignal.state.SignalProtocolStore; import org.whispersystems.libsignal.state.SignedPreKeyRecord; import org.whispersystems.libsignal.state.SignedPreKeyStore; import org.whispersystems.signalservice.api.SignalServiceProtocolStore; @@ -172,7 +170,7 @@ public class SignalProtocolStoreImpl implements SignalServiceProtocolStore { } @Override - public void clearSenderKeySharedWith(DistributionId distributionId, Collection addresses) { - senderKeyStore.clearSenderKeySharedWith(distributionId, addresses); + public void clearSenderKeySharedWith(Collection addresses) { + senderKeyStore.clearSenderKeySharedWith(addresses); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalSenderKeyStore.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalSenderKeyStore.java index e488bc89c9..6a8b9cf33f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalSenderKeyStore.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalSenderKeyStore.java @@ -62,9 +62,9 @@ public final class SignalSenderKeyStore implements SignalServiceSenderKeyStore { } @Override - public void clearSenderKeySharedWith(DistributionId distributionId, Collection addresses) { + public void clearSenderKeySharedWith(Collection addresses) { synchronized (LOCK) { - DatabaseFactory.getSenderKeySharedDatabase(context).delete(distributionId, addresses); + DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(addresses); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SenderKeySharedDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SenderKeySharedDatabase.java index a9bdfb823d..c732229d29 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SenderKeySharedDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SenderKeySharedDatabase.java @@ -118,7 +118,26 @@ public class SenderKeySharedDatabase extends Database { } /** - * Clear all shared statuses for a given recipientId. + * Clear the shared status for all distributionIds for a set of addresses. + */ + public void deleteAllFor(@NonNull Collection addresses) { + SQLiteDatabase db = databaseHelper.getWritableDatabase(); + String query = ADDRESS + " = ? AND " + DEVICE + " = ?"; + + db.beginTransaction(); + try { + for (SignalProtocolAddress address : addresses) { + db.delete(TABLE_NAME, query, SqlUtil.buildArgs(address.getName(), address.getDeviceId())); + } + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + } + + /** + * Clear the shared status for all distributionIds for a given recipientId. */ public void deleteAllFor(@NonNull RecipientId recipientId) { SQLiteDatabase db = databaseHelper.getWritableDatabase(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/GroupSendUtil.java b/app/src/main/java/org/thoughtcrime/securesms/messages/GroupSendUtil.java index 107d7b910a..441cc9e5fa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/GroupSendUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/GroupSendUtil.java @@ -252,7 +252,7 @@ public final class GroupSendUtil { allResults.addAll(results); int successCount = (int) results.stream().filter(SendMessageResult::isSuccess).count(); - Log.d(TAG, "Successfully using 1:1 to " + successCount + "/" + targets.size() + " legacy targets."); + Log.d(TAG, "Successfully sent using 1:1 to " + successCount + "/" + targets.size() + " legacy targets."); } return allResults; diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java index 6e3d1e8782..579bc22400 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageSender.java @@ -119,6 +119,7 @@ import java.io.IOException; import java.io.InputStream; import java.security.SecureRandom; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -1800,20 +1801,12 @@ public class SignalServiceMessageSender { for (GroupMismatchedDevices mismatched : e.getMismatchedDevices()) { SignalServiceAddress address = new SignalServiceAddress(UuidUtil.parse(mismatched.getUuid()), Optional.absent()); handleMismatchedDevices(socket, address, mismatched.getDevices()); - List clearAddresses = mismatched.getDevices().getExtraDevices().stream() - .map(device -> new SignalProtocolAddress(address.getIdentifier(), device)) - .collect(Collectors.toList()); - store.clearSenderKeySharedWith(distributionId, clearAddresses); } } catch (GroupStaleDevicesException e) { Log.w(TAG, "[sendGroupMessage] Handling stale devices.", e); for (GroupStaleDevices stale : e.getStaleDevices()) { SignalServiceAddress address = new SignalServiceAddress(UuidUtil.parse(stale.getUuid()), Optional.absent()); handleStaleDevices(address, stale.getDevices()); - List clearAddresses = stale.getDevices().getStaleDevices().stream() - .map(device -> new SignalProtocolAddress(address.getIdentifier(), device)) - .collect(Collectors.toList()); - store.clearSenderKeySharedWith(distributionId, clearAddresses); } } @@ -1998,14 +1991,7 @@ public class SignalServiceMessageSender { throws IOException, UntrustedIdentityException { try { - for (int extraDeviceId : mismatchedDevices.getExtraDevices()) { - if (recipient.getUuid().isPresent()) { - store.archiveSession(new SignalProtocolAddress(recipient.getUuid().get().toString(), extraDeviceId)); - } - if (recipient.getNumber().isPresent()) { - store.archiveSession(new SignalProtocolAddress(recipient.getNumber().get(), extraDeviceId)); - } - } + archiveSessions(recipient, mismatchedDevices.getExtraDevices()); for (int missingDeviceId : mismatchedDevices.getMissingDevices()) { PreKeyBundle preKey = socket.getPreKey(recipient, missingDeviceId); @@ -2023,14 +2009,32 @@ public class SignalServiceMessageSender { } private void handleStaleDevices(SignalServiceAddress recipient, StaleDevices staleDevices) { - for (int staleDeviceId : staleDevices.getStaleDevices()) { + archiveSessions(recipient, staleDevices.getStaleDevices()); + } + + private void archiveSessions(SignalServiceAddress recipient, List devices) { + List addressesToClear = convertToProtocolAddresses(recipient, devices); + + for (SignalProtocolAddress address : addressesToClear) { + store.archiveSession(address); + } + + store.clearSenderKeySharedWith(addressesToClear); + } + + private List convertToProtocolAddresses(SignalServiceAddress recipient, List devices) { + List addresses = new ArrayList<>(devices.size()); + + for (int staleDeviceId : devices) { if (recipient.getUuid().isPresent()) { - store.archiveSession(new SignalProtocolAddress(recipient.getUuid().get().toString(), staleDeviceId)); + addresses.add(new SignalProtocolAddress(recipient.getUuid().get().toString(), staleDeviceId)); } if (recipient.getNumber().isPresent()) { - store.archiveSession(new SignalProtocolAddress(recipient.getNumber().get(), staleDeviceId)); + addresses.add(new SignalProtocolAddress(recipient.getNumber().get(), staleDeviceId)); } } + + return addresses; } private Optional getTargetUnidentifiedAccess(Optional unidentifiedAccess) { diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceSenderKeyStore.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceSenderKeyStore.java index 49dd327f2c..db91b2d0a9 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceSenderKeyStore.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceSenderKeyStore.java @@ -23,7 +23,7 @@ public interface SignalServiceSenderKeyStore extends SenderKeyStore { void markSenderKeySharedWith(DistributionId distributionId, Collection addresses); /** - * Marks the provided addresses as not knowing about the provided distributionId. + * Marks the provided addresses as not knowing about any distributionIds. */ - void clearSenderKeySharedWith(DistributionId distributionId, Collection addresses); + void clearSenderKeySharedWith(Collection addresses); }