diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/error/SafetyNumberChangeRepository.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/error/SafetyNumberChangeRepository.java index 652280a5a..f8c4f1e5f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/error/SafetyNumberChangeRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/error/SafetyNumberChangeRepository.java @@ -13,6 +13,7 @@ import com.annimon.stream.Stream; import org.signal.core.util.concurrent.SignalExecutors; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.crypto.DatabaseSessionLock; +import org.thoughtcrime.securesms.crypto.SessionUtil; import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.IdentityDatabase; @@ -126,8 +127,13 @@ final class SafetyNumberChangeRepository { SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(changedRecipient.getRecipient().requireServiceId(), 1); TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(context); Log.d(TAG, "Saving identity for: " + changedRecipient.getRecipient().getId() + " " + changedRecipient.getIdentityRecord().getIdentityKey().hashCode()); - boolean result = identityKeyStore.saveIdentity(mismatchAddress, changedRecipient.getIdentityRecord().getIdentityKey(), true); + TextSecureIdentityKeyStore.SaveResult result = identityKeyStore.saveIdentity(mismatchAddress, changedRecipient.getIdentityRecord().getIdentityKey(), true); Log.d(TAG, "Saving identity result: " + result); + if (result == TextSecureIdentityKeyStore.SaveResult.NO_CHANGE) { + Log.i(TAG, "Archiving sessions explicitly as they appear to be out of sync."); + SessionUtil.archiveSiblingSessions(context, mismatchAddress); + DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(changedRecipient.getRecipient().getId()); + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureIdentityKeyStore.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureIdentityKeyStore.java index e861b5713..5cd36972f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureIdentityKeyStore.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureIdentityKeyStore.java @@ -2,6 +2,8 @@ package org.thoughtcrime.securesms.crypto.storage; import android.content.Context; +import androidx.annotation.NonNull; + import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.crypto.DatabaseSessionLock; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; @@ -46,7 +48,7 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore { return TextSecurePreferences.getLocalRegistrationId(context); } - public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey, boolean nonBlockingApproval) { + public @NonNull SaveResult saveIdentity(SignalProtocolAddress address, IdentityKey identityKey, boolean nonBlockingApproval) { try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) { IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context); RecipientId recipientId = RecipientId.fromExternalPush(address.getName()); @@ -55,13 +57,11 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore { if (!identityRecord.isPresent()) { Log.i(TAG, "Saving new identity..."); identityDatabase.saveIdentity(recipientId, identityKey, VerifiedStatus.DEFAULT, true, System.currentTimeMillis(), nonBlockingApproval); - return false; + return SaveResult.NEW; } - Log.i(TAG, "Existing: " + identityRecord.get().getIdentityKey().hashCode() + " New: " + identityKey.hashCode()); - if (!identityRecord.get().getIdentityKey().equals(identityKey)) { - Log.i(TAG, "Replacing existing identity..."); + Log.i(TAG, "Replacing existing identity... Existing: " + identityRecord.get().getIdentityKey().hashCode() + " New: " + identityKey.hashCode()); VerifiedStatus verifiedStatus; if (identityRecord.get().getVerifiedStatus() == VerifiedStatus.VERIFIED || @@ -76,22 +76,22 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore { IdentityUtil.markIdentityUpdate(context, recipientId); SessionUtil.archiveSiblingSessions(context, address); DatabaseFactory.getSenderKeySharedDatabase(context).deleteAllFor(recipientId); - return true; + return SaveResult.UPDATE; } if (isNonBlockingApprovalRequired(identityRecord.get())) { Log.i(TAG, "Setting approval status..."); identityDatabase.setApproval(recipientId, nonBlockingApproval); - return false; + return SaveResult.NON_BLOCKING_APPROVAL_REQUIRED; } - return false; + return SaveResult.NO_CHANGE; } } @Override public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey) { - return saveIdentity(address, identityKey, false); + return saveIdentity(address, identityKey, false) == SaveResult.UPDATE; } @Override @@ -146,7 +146,7 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore { } if (!identityKey.equals(identityRecord.get().getIdentityKey())) { - Log.w(TAG, "Identity keys don't match... service: " + identityRecord.get().getIdentityKey().hashCode() + " database: " + identityRecord.get().getIdentityKey().hashCode()); + Log.w(TAG, "Identity keys don't match... service: " + identityKey.hashCode() + " database: " + identityRecord.get().getIdentityKey().hashCode()); return false; } @@ -168,4 +168,11 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore { System.currentTimeMillis() - identityRecord.getTimestamp() < TimeUnit.SECONDS.toMillis(TIMESTAMP_THRESHOLD_SECONDS) && !identityRecord.isApprovedNonBlocking(); } + + public enum SaveResult { + NEW, + UPDATE, + NON_BLOCKING_APPROVAL_REQUIRED, + NO_CHANGE + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java index fa8711eb5..4b080cbdd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java @@ -32,6 +32,7 @@ import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.groups.GroupManager; import org.thoughtcrime.securesms.jobs.GroupCallUpdateSendJob; +import org.thoughtcrime.securesms.jobs.RetrieveProfileJob; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientUtil; @@ -549,6 +550,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. callMessage); } catch (UntrustedIdentityException e) { Log.i(TAG, "sendOpaqueCallMessage onFailure: ", e); + RetrieveProfileJob.enqueue(recipient.getId()); process((s, p) -> p.handleGroupMessageSentError(s, new RemotePeer(recipient.getId()), UNTRUSTED_IDENTITY, Optional.fromNullable(e.getIdentityKey()))); } catch (IOException e) { Log.i(TAG, "sendOpaqueCallMessage onFailure: ", e); @@ -730,6 +732,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. callMessage); process((s, p) -> p.handleMessageSentSuccess(s, remotePeer.getCallId())); } catch (UntrustedIdentityException e) { + RetrieveProfileJob.enqueue(remotePeer.getId()); processSendMessageFailureWithChangeDetection(remotePeer, (s, p) -> p.handleMessageSentError(s, remotePeer.getCallId(),