From ca0e52e141d19eccb22505235b9f7ccb7662fe5c Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Thu, 8 Sep 2022 09:56:41 -0400 Subject: [PATCH] Fix bug with stale linked devices when changing number. --- .../changenumber/ChangeNumberViewModelTest.kt | 104 ++++++++++++ .../RecipientDatabaseTest_processPnpTuple.kt | 2 +- .../helpers/migration/MyStoryMigrationTest.kt | 2 +- ...umentationApplicationDependencyProvider.kt | 1 + .../securesms/testing/MockProvider.kt | 28 ++++ .../changenumber/ChangeNumberRepository.kt | 152 ++++++++++++------ .../push/SignalServiceNetworkAccess.kt | 2 +- .../api/SignalServiceMessageSender.java | 6 + .../internal/push/MismatchedDevices.java | 4 +- .../internal/push/OutgoingPushMessage.java | 2 + .../internal/push/PreKeyResponse.java | 4 +- .../internal/push/PreKeyResponseItem.java | 8 +- 12 files changed, 251 insertions(+), 64 deletions(-) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModelTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModelTest.kt index a02f8220e..1e065044a 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModelTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberViewModelTest.kt @@ -34,6 +34,7 @@ import org.thoughtcrime.securesms.testing.success import org.thoughtcrime.securesms.testing.timeout import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.internal.push.MismatchedDevices import org.whispersystems.signalservice.internal.push.PreKeyState import java.util.UUID @@ -249,6 +250,109 @@ class ChangeNumberViewModelTest { assertSuccess(newPni, changeNumberRequest, setPreKeysRequest) } + @Test + fun testChangeNumber_givenMismatchedDevicesOnFirstCall() { + // GIVEN + val aci = Recipient.self().requireServiceId() + val newPni = ServiceId.from(UUID.randomUUID()) + lateinit var changeNumberRequest: ChangePhoneNumberRequest + lateinit var setPreKeysRequest: PreKeyState + + InstrumentationApplicationDependencyProvider.addMockWebRequestHandlers( + Get("/v1/devices") { MockResponse().success(MockProvider.primaryOnlyDeviceList) }, + Put("/v1/accounts/number") { r -> + changeNumberRequest = r.parsedRequestBody() + if (changeNumberRequest.deviceMessages.isEmpty()) { + MockResponse().failure( + 409, + MismatchedDevices().apply { + missingDevices = listOf(2) + extraDevices = emptyList() + } + ) + } else { + MockResponse().success(MockProvider.createVerifyAccountResponse(aci, newPni)) + } + }, + Get("/v2/keys/$aci/2") { + MockResponse().success(MockProvider.createPreKeyResponse(deviceId = 2)) + }, + Put("/v2/keys") { r -> + setPreKeysRequest = r.parsedRequestBody() + MockResponse().success() + }, + Get("/v1/certificate/delivery") { MockResponse().success(MockProvider.senderCertificate) } + ) + + // WHEN + viewModel.verifyCodeWithoutRegistrationLock("123456").blockingGet().resultOrThrow + + // THEN + assertSuccess(newPni, changeNumberRequest, setPreKeysRequest) + } + + @Test + fun testChangeNumber_givenRegLockAndMismatchedDevicesOnFirstTwoCalls() { + // GIVEN + val aci = Recipient.self().requireServiceId() + val newPni = ServiceId.from(UUID.randomUUID()) + + lateinit var changeNumberRequest: ChangePhoneNumberRequest + lateinit var setPreKeysRequest: PreKeyState + + MockProvider.mockGetRegistrationLockStringFlow(kbsRepository) + + InstrumentationApplicationDependencyProvider.addMockWebRequestHandlers( + Put("/v1/accounts/number") { r -> + changeNumberRequest = r.parsedRequestBody() + if (changeNumberRequest.registrationLock.isNullOrEmpty()) { + MockResponse().failure(423, MockProvider.lockedFailure) + } else if (changeNumberRequest.deviceMessages.isEmpty()) { + MockResponse().failure( + 409, + MismatchedDevices().apply { + missingDevices = listOf(2) + extraDevices = emptyList() + } + ) + } else if (changeNumberRequest.deviceMessages.size == 1) { + MockResponse().failure( + 409, + MismatchedDevices().apply { + missingDevices = listOf(2, 3) + extraDevices = emptyList() + } + ) + } else { + MockResponse().success(MockProvider.createVerifyAccountResponse(aci, newPni)) + } + }, + Get("/v2/keys/$aci/2") { + MockResponse().success(MockProvider.createPreKeyResponse(deviceId = 2)) + }, + Get("/v2/keys/$aci/3") { + MockResponse().success(MockProvider.createPreKeyResponse(deviceId = 3)) + }, + Put("/v2/keys") { r -> + setPreKeysRequest = r.parsedRequestBody() + MockResponse().success() + }, + Get("/v1/certificate/delivery") { MockResponse().success(MockProvider.senderCertificate) } + ) + + // WHEN + viewModel.verifyCodeWithoutRegistrationLock("123456").blockingGet().also { processor -> + processor.registrationLock() assertIs true + Recipient.self().requirePni() assertIsNot newPni + SignalStore.misc().pendingChangeNumberMetadata.assertIsNull() + } + + viewModel.verifyCodeAndRegisterAccountWithRegistrationLock("pin").blockingGet().resultOrThrow + + // THEN + assertSuccess(newPni, changeNumberRequest, setPreKeysRequest) + } + private fun assertSuccess(newPni: ServiceId, changeNumberRequest: ChangePhoneNumberRequest, setPreKeysRequest: PreKeyState) { val pniProtocolStore = ApplicationDependencies.getProtocolStore().pni() val pniMetadataStore = SignalStore.account().pniPreKeys diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientDatabaseTest_processPnpTuple.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientDatabaseTest_processPnpTuple.kt index 83c0fd177..d1f5c98d3 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientDatabaseTest_processPnpTuple.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientDatabaseTest_processPnpTuple.kt @@ -410,7 +410,7 @@ class RecipientDatabaseTest_processPnpTuple { fun process(e164: String?, pni: PNI?, aci: ACI?) { SignalDatabase.rawDatabase.beginTransaction() try { - generatedIds += recipientDatabase.processPnpTuple(e164, pni, aci, pniVerified = false, pnpEnabled = true).finalId + generatedIds += recipientDatabase.processPnpTuple(e164, pni, aci, pniVerified = false).finalId SignalDatabase.rawDatabase.setTransactionSuccessful() } finally { SignalDatabase.rawDatabase.endTransaction() diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/helpers/migration/MyStoryMigrationTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/helpers/migration/MyStoryMigrationTest.kt index bf37a0504..bcb7ef66f 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/helpers/migration/MyStoryMigrationTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/helpers/migration/MyStoryMigrationTest.kt @@ -109,7 +109,7 @@ class MyStoryMigrationTest { } private fun runMigration() { - MyStoryMigration.migrate( + V151_MyStoryMigration.migrate( InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as Application, SignalDatabase.rawDatabase, 0, diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/dependencies/InstrumentationApplicationDependencyProvider.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/dependencies/InstrumentationApplicationDependencyProvider.kt index bc1dd5f12..506525077 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/dependencies/InstrumentationApplicationDependencyProvider.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/dependencies/InstrumentationApplicationDependencyProvider.kt @@ -77,6 +77,7 @@ class InstrumentationApplicationDependencyProvider(application: Application, def serviceNetworkAccessMock = mock { on { getConfiguration() } doReturn uncensoredConfiguration on { getConfiguration(any()) } doReturn uncensoredConfiguration + on { uncensoredConfiguration } doReturn uncensoredConfiguration } keyBackupService = mock() diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MockProvider.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MockProvider.kt index 825b84838..7c07dc3d5 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MockProvider.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/MockProvider.kt @@ -6,7 +6,14 @@ import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.stub import org.signal.core.util.Hex +import org.signal.libsignal.protocol.IdentityKeyPair +import org.signal.libsignal.protocol.ecc.Curve +import org.signal.libsignal.protocol.state.PreKeyRecord +import org.signal.libsignal.protocol.util.KeyHelper +import org.signal.libsignal.protocol.util.Medium +import org.thoughtcrime.securesms.crypto.PreKeyUtil import org.thoughtcrime.securesms.dependencies.ApplicationDependencies +import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.pin.KbsRepository import org.thoughtcrime.securesms.pin.TokenData import org.thoughtcrime.securesms.test.BuildConfig @@ -16,10 +23,14 @@ import org.whispersystems.signalservice.api.kbs.HashedPin import org.whispersystems.signalservice.api.kbs.MasterKey import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo import org.whispersystems.signalservice.api.push.ServiceId +import org.whispersystems.signalservice.api.push.SignedPreKeyEntity import org.whispersystems.signalservice.internal.ServiceResponse import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse import org.whispersystems.signalservice.internal.push.AuthCredentials import org.whispersystems.signalservice.internal.push.DeviceInfoList +import org.whispersystems.signalservice.internal.push.PreKeyEntity +import org.whispersystems.signalservice.internal.push.PreKeyResponse +import org.whispersystems.signalservice.internal.push.PreKeyResponseItem import org.whispersystems.signalservice.internal.push.PushServiceSocket import org.whispersystems.signalservice.internal.push.SenderCertificate import org.whispersystems.signalservice.internal.push.VerifyAccountResponse @@ -83,4 +94,21 @@ object MockProvider { on { newRegistrationSession(any(), any()) } doReturn session } } + + fun createPreKeyResponse(identity: IdentityKeyPair = SignalStore.account().aciIdentityKey, deviceId: Int): PreKeyResponse { + val signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(SecureRandom().nextInt(Medium.MAX_VALUE), identity.privateKey) + val oneTimePreKey = PreKeyRecord(SecureRandom().nextInt(Medium.MAX_VALUE), Curve.generateKeyPair()) + + val device = PreKeyResponseItem().apply { + this.deviceId = deviceId + registrationId = KeyHelper.generateRegistrationId(false) + signedPreKey = SignedPreKeyEntity(signedPreKeyRecord.id, signedPreKeyRecord.keyPair.publicKey, signedPreKeyRecord.signature) + preKey = PreKeyEntity(oneTimePreKey.id, oneTimePreKey.keyPair.publicKey) + } + + return PreKeyResponse().apply { + identityKey = identity.publicKey + devices = listOf(device) + } + } } 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 63e1f9e7a..3f77a4a97 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 @@ -6,12 +6,12 @@ import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.schedulers.Schedulers import org.signal.core.util.logging.Log import org.signal.libsignal.protocol.IdentityKeyPair +import org.signal.libsignal.protocol.SignalProtocolAddress import org.signal.libsignal.protocol.state.SignalProtocolStore import org.signal.libsignal.protocol.util.KeyHelper import org.signal.libsignal.protocol.util.Medium import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.crypto.PreKeyUtil -import org.thoughtcrime.securesms.crypto.storage.PreKeyMetadataStore import org.thoughtcrime.securesms.database.IdentityDatabase import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.model.databaseprotos.PendingChangeNumberMetadata @@ -30,7 +30,6 @@ import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException import org.whispersystems.signalservice.api.SignalServiceAccountManager import org.whispersystems.signalservice.api.SignalServiceMessageSender import org.whispersystems.signalservice.api.account.ChangePhoneNumberRequest -import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo import org.whispersystems.signalservice.api.push.PNI import org.whispersystems.signalservice.api.push.ServiceId import org.whispersystems.signalservice.api.push.ServiceIdType @@ -41,13 +40,17 @@ import org.whispersystems.signalservice.internal.push.OutgoingPushMessage import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage import org.whispersystems.signalservice.internal.push.VerifyAccountResponse import org.whispersystems.signalservice.internal.push.WhoAmIResponse +import org.whispersystems.signalservice.internal.push.exceptions.MismatchedDevicesException import java.io.IOException import java.security.MessageDigest import java.security.SecureRandom private val TAG: String = Log.tag(ChangeNumberRepository::class.java) -class ChangeNumberRepository(private val accountManager: SignalServiceAccountManager = ApplicationDependencies.getSignalServiceAccountManager()) { +class ChangeNumberRepository( + private val accountManager: SignalServiceAccountManager = ApplicationDependencies.getSignalServiceAccountManager(), + private val messageSender: SignalServiceMessageSender = ApplicationDependencies.getSignalServiceMessageSender() +) { fun ensureDecryptionsDrained(): Completable { return Completable.create { emitter -> @@ -61,9 +64,26 @@ class ChangeNumberRepository(private val accountManager: SignalServiceAccountMan fun changeNumber(code: String, newE164: String): Single> { return Single.fromCallable { - val (request: ChangePhoneNumberRequest, metadata: PendingChangeNumberMetadata) = createChangeNumberRequest(code, newE164, null) - SignalStore.misc().setPendingChangeNumberMetadata(metadata) - accountManager.changeNumber(request) + var completed = false + var attempts = 0 + lateinit var changeNumberResponse: ServiceResponse + + while (!completed && attempts < 5) { + val (request: ChangePhoneNumberRequest, metadata: PendingChangeNumberMetadata) = createChangeNumberRequest(code, newE164, null) + SignalStore.misc().setPendingChangeNumberMetadata(metadata) + + changeNumberResponse = accountManager.changeNumber(request) + + val possibleError: Throwable? = changeNumberResponse.applicationError.orElse(null) + if (possibleError is MismatchedDevicesException) { + messageSender.handleChangeNumberMismatchDevices(possibleError.mismatchedDevices) + attempts++ + } else { + completed = true + } + } + + changeNumberResponse }.subscribeOn(Schedulers.io()) .onErrorReturn { t -> ServiceResponse.forExecutionError(t) } } @@ -75,22 +95,40 @@ class ChangeNumberRepository(private val accountManager: SignalServiceAccountMan tokenData: TokenData ): Single> { return Single.fromCallable { - try { - val kbsData: KbsPinData = KbsRepository.restoreMasterKey(pin, tokenData.enclave, tokenData.basicAuth, tokenData.tokenResponse)!! - val registrationLock: String = kbsData.masterKey.deriveRegistrationLock() - val (request: ChangePhoneNumberRequest, metadata: PendingChangeNumberMetadata) = createChangeNumberRequest(code, newE164, registrationLock) + val kbsData: KbsPinData + val registrationLock: String + try { + kbsData = KbsRepository.restoreMasterKey(pin, tokenData.enclave, tokenData.basicAuth, tokenData.tokenResponse)!! + registrationLock = kbsData.masterKey.deriveRegistrationLock() + } catch (e: KeyBackupSystemWrongPinException) { + return@fromCallable ServiceResponse.forExecutionError(e) + } catch (e: KeyBackupSystemNoDataException) { + return@fromCallable ServiceResponse.forExecutionError(e) + } catch (e: IOException) { + return@fromCallable ServiceResponse.forExecutionError(e) + } + + var completed = false + var attempts = 0 + lateinit var changeNumberResponse: ServiceResponse + + while (!completed && attempts < 5) { + val (request: ChangePhoneNumberRequest, metadata: PendingChangeNumberMetadata) = createChangeNumberRequest(code, newE164, registrationLock) SignalStore.misc().setPendingChangeNumberMetadata(metadata) - val response: ServiceResponse = accountManager.changeNumber(request) - VerifyAccountRepository.VerifyAccountWithRegistrationLockResponse.from(response, kbsData) - } catch (e: KeyBackupSystemWrongPinException) { - ServiceResponse.forExecutionError(e) - } catch (e: KeyBackupSystemNoDataException) { - ServiceResponse.forExecutionError(e) - } catch (e: IOException) { - ServiceResponse.forExecutionError(e) + changeNumberResponse = accountManager.changeNumber(request) + + val possibleError: Throwable? = changeNumberResponse.applicationError.orElse(null) + if (possibleError is MismatchedDevicesException) { + messageSender.handleChangeNumberMismatchDevices(possibleError.mismatchedDevices) + attempts++ + } else { + completed = true + } } + + VerifyAccountRepository.VerifyAccountWithRegistrationLockResponse.from(changeNumberResponse, kbsData) }.subscribeOn(Schedulers.io()) .onErrorReturn { t -> ServiceResponse.forExecutionError(t) } } @@ -199,49 +237,57 @@ class ChangeNumberRepository(private val accountManager: SignalServiceAccountMan newE164: String, registrationLock: String? ): ChangeNumberRequestData { - val messageSender: SignalServiceMessageSender = ApplicationDependencies.getSignalServiceMessageSender() - val pniProtocolStore: SignalProtocolStore = ApplicationDependencies.getProtocolStore().pni() - val pniMetadataStore: PreKeyMetadataStore = SignalStore.account().pniPreKeys - - val devices: List = accountManager.getDevices() + val selfIdentifier: String = SignalStore.account().requireAci().toString() + val aciProtocolStore: SignalProtocolStore = ApplicationDependencies.getProtocolStore().aci() val pniIdentity: IdentityKeyPair = IdentityKeyUtil.generateIdentityKeyPair() val deviceMessages = mutableListOf() - val devicePniSignedPreKeys = mutableMapOf() - val pniRegistrationIds = mutableMapOf() - val primaryDeviceId = SignalServiceAddress.DEFAULT_DEVICE_ID.toString() + val devicePniSignedPreKeys = mutableMapOf() + val pniRegistrationIds = mutableMapOf() + val primaryDeviceId: Int = SignalServiceAddress.DEFAULT_DEVICE_ID - for (device in devices) { - val deviceId = device.id.toString() + val devices: List = listOf(primaryDeviceId) + aciProtocolStore.getSubDeviceSessions(selfIdentifier) - // Signed Prekeys - val signedPreKeyRecord = if (deviceId == primaryDeviceId) { - PreKeyUtil.generateAndStoreSignedPreKey(pniProtocolStore, pniMetadataStore, pniIdentity.privateKey) - } else { - PreKeyUtil.generateSignedPreKey(SecureRandom().nextInt(Medium.MAX_VALUE), pniIdentity.privateKey) + devices + .filter { it == primaryDeviceId || aciProtocolStore.containsSession(SignalProtocolAddress(selfIdentifier, it)) } + .forEach { deviceId -> + // Signed Prekeys + val signedPreKeyRecord = if (deviceId == primaryDeviceId) { + PreKeyUtil.generateAndStoreSignedPreKey(ApplicationDependencies.getProtocolStore().pni(), SignalStore.account().pniPreKeys, pniIdentity.privateKey) + } else { + PreKeyUtil.generateSignedPreKey(SecureRandom().nextInt(Medium.MAX_VALUE), pniIdentity.privateKey) + } + devicePniSignedPreKeys[deviceId] = SignedPreKeyEntity(signedPreKeyRecord.id, signedPreKeyRecord.keyPair.publicKey, signedPreKeyRecord.signature) + + // Registration Ids + var pniRegistrationId = -1 + while (pniRegistrationId < 0 || pniRegistrationIds.values.contains(pniRegistrationId)) { + pniRegistrationId = KeyHelper.generateRegistrationId(false) + } + pniRegistrationIds[deviceId] = pniRegistrationId + + // Device Messages + if (deviceId != primaryDeviceId) { + val pniChangeNumber = SyncMessage.PniChangeNumber.newBuilder() + .setIdentityKeyPair(pniIdentity.serialize().toProtoByteString()) + .setSignedPreKey(signedPreKeyRecord.serialize().toProtoByteString()) + .setRegistrationId(pniRegistrationId) + .build() + + deviceMessages += messageSender.getEncryptedSyncPniChangeNumberMessage(deviceId, pniChangeNumber) + } } - devicePniSignedPreKeys[deviceId] = SignedPreKeyEntity(signedPreKeyRecord.id, signedPreKeyRecord.keyPair.publicKey, signedPreKeyRecord.signature) - // Registration Ids - var pniRegistrationId = -1 - while (pniRegistrationId < 0 || pniRegistrationIds.values.contains(pniRegistrationId)) { - pniRegistrationId = KeyHelper.generateRegistrationId(false) - } - pniRegistrationIds[deviceId] = pniRegistrationId + val request = ChangePhoneNumberRequest( + newE164, + code, + registrationLock, + pniIdentity.publicKey, + deviceMessages, + devicePniSignedPreKeys.mapKeys { it.key.toString() }, + pniRegistrationIds.mapKeys { it.key.toString() } + ) - // Device Messages - if (deviceId != primaryDeviceId) { - val pniChangeNumber = SyncMessage.PniChangeNumber.newBuilder() - .setIdentityKeyPair(pniIdentity.serialize().toProtoByteString()) - .setSignedPreKey(signedPreKeyRecord.serialize().toProtoByteString()) - .setRegistrationId(pniRegistrationId) - .build() - - deviceMessages += messageSender.getEncryptedSyncPniChangeNumberMessage(device.id, pniChangeNumber) - } - } - - val request = ChangePhoneNumberRequest(newE164, code, registrationLock, pniIdentity.publicKey, deviceMessages, devicePniSignedPreKeys, pniRegistrationIds) val metadata = PendingChangeNumberMetadata.newBuilder() .setPreviousPni(SignalStore.account().pni!!.toByteString()) .setPniIdentityKeyPair(pniIdentity.serialize().toProtoByteString()) diff --git a/app/src/main/java/org/thoughtcrime/securesms/push/SignalServiceNetworkAccess.kt b/app/src/main/java/org/thoughtcrime/securesms/push/SignalServiceNetworkAccess.kt index 127c4c383..514688559 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/push/SignalServiceNetworkAccess.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/push/SignalServiceNetworkAccess.kt @@ -211,7 +211,7 @@ open class SignalServiceNetworkAccess(context: Context) { COUNTRY_CODE_UZBEKISTAN, ) - val uncensoredConfiguration: SignalServiceConfiguration = SignalServiceConfiguration( + open val uncensoredConfiguration: SignalServiceConfiguration = SignalServiceConfiguration( arrayOf(SignalServiceUrl(BuildConfig.SIGNAL_URL, serviceTrustStore)), mapOf( 0 to arrayOf(SignalCdnUrl(BuildConfig.SIGNAL_CDN_URL, serviceTrustStore)), 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 b57bbdb7a..1c3d4bd96 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 @@ -2235,6 +2235,12 @@ public class SignalServiceMessageSender { archiveSessions(recipient, staleDevices.getStaleDevices()); } + public void handleChangeNumberMismatchDevices(@Nonnull MismatchedDevices mismatchedDevices) + throws IOException, UntrustedIdentityException + { + handleMismatchedDevices(socket, localAddress, mismatchedDevices); + } + private void archiveSessions(SignalServiceAddress recipient, List devices) { List addressesToClear = convertToProtocolAddresses(recipient, devices); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/MismatchedDevices.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/MismatchedDevices.java index 3d4dfefa0..16127ecec 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/MismatchedDevices.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/MismatchedDevices.java @@ -12,10 +12,10 @@ import java.util.List; public class MismatchedDevices { @JsonProperty - private List missingDevices; + public List missingDevices; @JsonProperty - private List extraDevices; + public List extraDevices; public List getMissingDevices() { return missingDevices; diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/OutgoingPushMessage.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/OutgoingPushMessage.java index 8cf9eae90..ed34b0454 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/OutgoingPushMessage.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/OutgoingPushMessage.java @@ -20,6 +20,8 @@ public class OutgoingPushMessage { @JsonProperty private String content; + public OutgoingPushMessage() {} + public OutgoingPushMessage(int type, int destinationDeviceId, int destinationRegistrationId, diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PreKeyResponse.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PreKeyResponse.java index 4b58258f4..b9ad9367c 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PreKeyResponse.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PreKeyResponse.java @@ -20,10 +20,10 @@ public class PreKeyResponse { @JsonProperty @JsonSerialize(using = JsonUtil.IdentityKeySerializer.class) @JsonDeserialize(using = JsonUtil.IdentityKeyDeserializer.class) - private IdentityKey identityKey; + public IdentityKey identityKey; @JsonProperty - private List devices; + public List devices; public IdentityKey getIdentityKey() { return identityKey; diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PreKeyResponseItem.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PreKeyResponseItem.java index 2f2641519..7c0af5723 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PreKeyResponseItem.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PreKeyResponseItem.java @@ -13,16 +13,16 @@ import org.whispersystems.signalservice.api.push.SignedPreKeyEntity; public class PreKeyResponseItem { @JsonProperty - private int deviceId; + public int deviceId; @JsonProperty - private int registrationId; + public int registrationId; @JsonProperty - private SignedPreKeyEntity signedPreKey; + public SignedPreKeyEntity signedPreKey; @JsonProperty - private PreKeyEntity preKey; + public PreKeyEntity preKey; public int getDeviceId() { return deviceId;