diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt index 5ba3ce55a0..2926ccfb09 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt @@ -276,6 +276,7 @@ class ChangeNumberRepository( pniProtocolStore.identities().saveIdentityWithoutSideEffects( Recipient.self().id, + pni, pniProtocolStore.identityKeyPair.publicKey, IdentityTable.VerifiedStatus.VERIFIED, true, diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStore.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStore.java index b4332aae2f..5cf4c7b570 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStore.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalBaseIdentityKeyStore.java @@ -112,18 +112,14 @@ public class SignalBaseIdentityKeyStore { } public void saveIdentityWithoutSideEffects(@NonNull RecipientId recipientId, + @NonNull ServiceId serviceId, IdentityKey identityKey, VerifiedStatus verifiedStatus, boolean firstUse, long timestamp, boolean nonBlockingApproval) { - Recipient recipient = Recipient.resolved(recipientId); - if (recipient.hasServiceId()) { - cache.save(recipient.requireServiceId().toString(), recipientId, identityKey, verifiedStatus, firstUse, timestamp, nonBlockingApproval); - } else { - Log.w(TAG, "[saveIdentity] No serviceId for " + recipient.getId(), new Throwable()); - } + cache.save(serviceId.toString(), recipientId, identityKey, verifiedStatus, firstUse, timestamp, nonBlockingApproval); } public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, IdentityKeyStore.Direction direction) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalIdentityKeyStore.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalIdentityKeyStore.java index bcc87702de..b632ce96c6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalIdentityKeyStore.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalIdentityKeyStore.java @@ -11,6 +11,7 @@ import org.thoughtcrime.securesms.database.identity.IdentityRecordList; import org.thoughtcrime.securesms.database.model.IdentityRecord; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; +import org.whispersystems.signalservice.api.push.ServiceId; import java.util.List; import java.util.Optional; @@ -50,13 +51,14 @@ public class SignalIdentityKeyStore implements IdentityKeyStore { } public void saveIdentityWithoutSideEffects(@NonNull RecipientId recipientId, + @NonNull ServiceId serviceId, IdentityKey identityKey, VerifiedStatus verifiedStatus, boolean firstUse, long timestamp, boolean nonBlockingApproval) { - baseStore.saveIdentityWithoutSideEffects(recipientId, identityKey, verifiedStatus, firstUse, timestamp, nonBlockingApproval); + baseStore.saveIdentityWithoutSideEffects(recipientId, serviceId, identityKey, verifiedStatus, firstUse, timestamp, nonBlockingApproval); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java index 35f45d2383..6a92543ee9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java @@ -52,6 +52,7 @@ import org.thoughtcrime.securesms.migrations.DeleteDeprecatedLogsMigrationJob; import org.thoughtcrime.securesms.migrations.DirectoryRefreshMigrationJob; import org.thoughtcrime.securesms.migrations.EmojiDownloadMigrationJob; import org.thoughtcrime.securesms.migrations.EmojiSearchIndexCheckMigrationJob; +import org.thoughtcrime.securesms.migrations.IdentityTableCleanupMigrationJob; import org.thoughtcrime.securesms.migrations.LegacyMigrationJob; import org.thoughtcrime.securesms.migrations.MigrationCompleteJob; import org.thoughtcrime.securesms.migrations.OptimizeMessageSearchIndexMigrationJob; @@ -236,6 +237,7 @@ public final class JobManagerFactories { put(DirectoryRefreshMigrationJob.KEY, new DirectoryRefreshMigrationJob.Factory()); put(EmojiDownloadMigrationJob.KEY, new EmojiDownloadMigrationJob.Factory()); put(EmojiSearchIndexCheckMigrationJob.KEY, new EmojiSearchIndexCheckMigrationJob.Factory()); + put(IdentityTableCleanupMigrationJob.KEY, new IdentityTableCleanupMigrationJob.Factory()); put(LegacyMigrationJob.KEY, new LegacyMigrationJob.Factory()); put(MigrationCompleteJob.KEY, new MigrationCompleteJob.Factory()); put(OptimizeMessageSearchIndexMigrationJob.KEY,new OptimizeMessageSearchIndexMigrationJob.Factory()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceContactSyncJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceContactSyncJob.kt index a5a2832ac2..279f948da2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceContactSyncJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/MultiDeviceContactSyncJob.kt @@ -103,14 +103,19 @@ class MultiDeviceContactSyncJob(parameters: Parameters, private val attachmentPo else -> VerifiedStatus.DEFAULT } - ApplicationDependencies.getProtocolStore().aci().identities().saveIdentityWithoutSideEffects( - recipient.id, - contact.verified.get().identityKey, - verifiedStatus, - false, - contact.verified.get().timestamp, - true - ) + if (recipient.serviceId.isPresent) { + ApplicationDependencies.getProtocolStore().aci().identities().saveIdentityWithoutSideEffects( + recipient.id, + recipient.serviceId.get(), + contact.verified.get().identityKey, + verifiedStatus, + false, + contact.verified.get().timestamp, + true + ) + } else { + Log.w(TAG, "Missing serviceId for ${recipient.id} -- cannot save identity!") + } } recipients.setBlocked(recipient.id, contact.isBlocked) diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java index 064eddc930..7b1e526181 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java @@ -135,9 +135,10 @@ public class ApplicationMigrations { static final int SVR2_MIRROR = 91; static final int ATTACHMENT_CLEANUP_3 = 92; static final int EMOJI_SEARCH_INDEX_CHECK = 93; + static final int IDENTITY_FIX = 94; } - public static final int CURRENT_VERSION = 93; + public static final int CURRENT_VERSION = 94; /** * This *must* be called after the {@link JobManager} has been instantiated, but *before* the call @@ -611,6 +612,10 @@ public class ApplicationMigrations { jobs.put(Version.EMOJI_SEARCH_INDEX_CHECK, new EmojiSearchIndexCheckMigrationJob()); } + if (lastSeenVersion < Version.IDENTITY_FIX) { + jobs.put(Version.IDENTITY_FIX, new IdentityTableCleanupMigrationJob()); + } + return jobs; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/IdentityTableCleanupMigrationJob.kt b/app/src/main/java/org/thoughtcrime/securesms/migrations/IdentityTableCleanupMigrationJob.kt new file mode 100644 index 0000000000..880a66dbfa --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/IdentityTableCleanupMigrationJob.kt @@ -0,0 +1,74 @@ +package org.thoughtcrime.securesms.migrations + +import org.signal.core.util.logging.Log +import org.thoughtcrime.securesms.database.IdentityTable +import org.thoughtcrime.securesms.dependencies.ApplicationDependencies +import org.thoughtcrime.securesms.jobmanager.Job +import org.thoughtcrime.securesms.jobs.AccountConsistencyWorkerJob +import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.recipients.Recipient + +/** + * Migration to help cleanup some inconsistent state for ourself in the identity table. + */ +internal class IdentityTableCleanupMigrationJob( + parameters: Parameters = Parameters.Builder().build() +) : MigrationJob(parameters) { + + companion object { + const val KEY = "IdentityTableCleanupMigrationJob" + + val TAG = Log.tag(IdentityTableCleanupMigrationJob::class.java) + } + + override fun getFactoryKey(): String = KEY + + override fun isUiBlocking(): Boolean = false + + override fun performMigration() { + if (SignalStore.account().aci == null || SignalStore.account().pni == null) { + Log.i(TAG, "ACI/PNI are unset, skipping.") + return + } + + if (!SignalStore.account().hasAciIdentityKey()) { + Log.i(TAG, "No ACI identity set yet, skipping.") + return + } + + if (!SignalStore.account().hasPniIdentityKey()) { + Log.i(TAG, "No PNI identity set yet, skipping.") + return + } + + ApplicationDependencies.getProtocolStore().aci().identities().saveIdentityWithoutSideEffects( + Recipient.self().id, + SignalStore.account().aci!!, + SignalStore.account().aciIdentityKey.publicKey, + IdentityTable.VerifiedStatus.VERIFIED, + true, + System.currentTimeMillis(), + true + ) + + ApplicationDependencies.getProtocolStore().pni().identities().saveIdentityWithoutSideEffects( + Recipient.self().id, + SignalStore.account().pni!!, + SignalStore.account().pniIdentityKey.publicKey, + IdentityTable.VerifiedStatus.VERIFIED, + true, + System.currentTimeMillis(), + true + ) + + ApplicationDependencies.getJobManager().add(AccountConsistencyWorkerJob()) + } + + override fun shouldRetry(e: Exception): Boolean = false + + class Factory : Job.Factory { + override fun create(parameters: Parameters, serializedData: ByteArray?): IdentityTableCleanupMigrationJob { + return IdentityTableCleanupMigrationJob(parameters) + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/RegistrationRepository.java b/app/src/main/java/org/thoughtcrime/securesms/registration/RegistrationRepository.java index 94c23a63e5..024c090672 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/RegistrationRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/RegistrationRepository.java @@ -40,6 +40,7 @@ import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.account.PreKeyCollection; import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.PNI; +import org.whispersystems.signalservice.api.push.ServiceId; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.util.Preconditions; import org.whispersystems.signalservice.internal.ServiceResponse; @@ -162,8 +163,8 @@ public final class RegistrationRepository { SignalStore.account().setFcmEnabled(registrationData.isFcm()); long now = System.currentTimeMillis(); - saveOwnIdentityKey(selfId, aciProtocolStore, now); - saveOwnIdentityKey(selfId, pniProtocolStore, now); + saveOwnIdentityKey(selfId, aci, aciProtocolStore, now); + saveOwnIdentityKey(selfId, pni, pniProtocolStore, now); SignalStore.account().setServicePassword(registrationData.getPassword()); SignalStore.account().setRegistered(true); @@ -200,8 +201,9 @@ public final class RegistrationRepository { metadataStore.setLastResortKyberPreKeyRotationTime(System.currentTimeMillis()); } - private void saveOwnIdentityKey(@NonNull RecipientId selfId, @NonNull SignalServiceAccountDataStoreImpl protocolStore, long now) { + private void saveOwnIdentityKey(@NonNull RecipientId selfId, @NonNull ServiceId serviceId, @NonNull SignalServiceAccountDataStoreImpl protocolStore, long now) { protocolStore.identities().saveIdentityWithoutSideEffects(selfId, + serviceId, protocolStore.getIdentityKeyPair().getPublicKey(), IdentityTable.VerifiedStatus.VERIFIED, true, diff --git a/app/src/main/java/org/thoughtcrime/securesms/verify/VerifyDisplayFragment.java b/app/src/main/java/org/thoughtcrime/securesms/verify/VerifyDisplayFragment.java index af3d8a1a6d..668755c186 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/verify/VerifyDisplayFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/verify/VerifyDisplayFragment.java @@ -543,6 +543,7 @@ public class VerifyDisplayFragment extends Fragment implements ViewTreeObserver. Log.i(TAG, "Saving identity: " + recipientId); ApplicationDependencies.getProtocolStore().aci().identities() .saveIdentityWithoutSideEffects(recipientId, + Recipient.resolved(recipientId).requireServiceId(), remoteIdentity, IdentityTable.VerifiedStatus.VERIFIED, false,