From eb7012b7aea46c085b5f9e26a952ae25c043e428 Mon Sep 17 00:00:00 2001 From: Michelle Tang Date: Tue, 5 Aug 2025 17:01:04 -0400 Subject: [PATCH] Remove plaintext device creation timestamp. --- .../securesms/linkdevice/Device.kt | 2 +- .../linkdevice/EditDeviceNameFragment.kt | 2 +- .../linkdevice/LinkDeviceFragment.kt | 16 ++++--- .../linkdevice/LinkDeviceRepository.kt | 46 +++++++++++++------ .../linkdevice/LinkDeviceSettingsState.kt | 4 +- .../linkdevice/LinkDeviceViewModel.kt | 25 +++++----- .../org/signal/core/util/IntExtensions.kt | 18 ++++++++ .../signalservice/api/link/LinkDeviceApi.kt | 8 ++-- .../SetLinkedDeviceTransferArchiveRequest.kt | 2 +- .../api/link/WaitForLinkedDeviceResponse.kt | 5 +- .../api/messages/multidevice/DeviceInfo.java | 19 +++++--- 11 files changed, 98 insertions(+), 49 deletions(-) create mode 100644 core-util-jvm/src/main/java/org/signal/core/util/IntExtensions.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/Device.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/Device.kt index c04b0a4fdd..6f548e4c86 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/Device.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/Device.kt @@ -3,4 +3,4 @@ package org.thoughtcrime.securesms.linkdevice /** * Class that represents a linked device */ -data class Device(val id: Int, val name: String?, val createdMillis: Long, val lastSeenMillis: Long) +data class Device(val id: Int, val name: String?, val createdMillis: Long?, val lastSeenMillis: Long, val registrationId: Int) diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/EditDeviceNameFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/EditDeviceNameFragment.kt index 155a56bebd..1432dc88a3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/EditDeviceNameFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/EditDeviceNameFragment.kt @@ -149,7 +149,7 @@ private fun DeviceListScreenLinkingPreview() { Previews.Preview { EditNameScreen( state = LinkDeviceSettingsState( - deviceToEdit = Device(1, "Laptop", 0, 0) + deviceToEdit = Device(1, "Laptop", 0, 0, 0) ) ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt index a5d662a01c..41046fd6d2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceFragment.kt @@ -495,7 +495,7 @@ fun DeviceListScreen( @Composable fun DeviceRow(device: Device, setDeviceToRemove: (Device) -> Unit, onEditDevice: (Device) -> Unit) { val titleString = if (device.name.isNullOrEmpty()) stringResource(R.string.DeviceListItem_unnamed_device) else device.name - val linkedDate = DateUtils.getDayPrecisionTimeSpanString(LocalContext.current, Locale.getDefault(), device.createdMillis) + val linkedDate = device.createdMillis?.let { DateUtils.getDayPrecisionTimeSpanString(LocalContext.current, Locale.getDefault(), device.createdMillis) } val lastActive = DateUtils.getDayPrecisionTimeSpanString(LocalContext.current, Locale.getDefault(), device.lastSeenMillis) val menuController = remember { DropdownMenus.MenuController() } Row( @@ -524,7 +524,9 @@ fun DeviceRow(device: Device, setDeviceToRemove: (Device) -> Unit, onEditDevice: .weight(1f) ) { Text(text = titleString, style = MaterialTheme.typography.bodyLarge) - Text(stringResource(R.string.DeviceListItem_linked_s, linkedDate), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + if (linkedDate != null) { + Text(stringResource(R.string.DeviceListItem_linked_s, linkedDate), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + } Text(stringResource(R.string.DeviceListItem_last_active_s, lastActive), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) } @@ -599,8 +601,8 @@ private fun DeviceListScreenPreview() { DeviceListScreen( state = LinkDeviceSettingsState( devices = listOf( - Device(1, "Sam's Macbook Pro", 1715793982000, 1716053182000), - Device(1, "Sam's iPad", 1715793182000, 1716053122000) + Device(1, "Sam's Macbook Pro", 1715793982000, 1716053182000, 0), + Device(1, "Sam's iPad", 1715793182000, 1716053122000, 0) ), seenQrEducationSheet = true ) @@ -653,7 +655,7 @@ private fun DeviceListScreenSyncingMessagesPreview() { Previews.Preview { DeviceListScreen( state = LinkDeviceSettingsState( - dialogState = DialogState.SyncingMessages(1, 1), + dialogState = DialogState.SyncingMessages(1), seenQrEducationSheet = true ) ) @@ -681,7 +683,7 @@ private fun DeviceListScreenSyncingFailedPreview() { state = LinkDeviceSettingsState( dialogState = DialogState.SyncingFailed( deviceId = 1, - deviceCreatedAt = 1, + deviceRegistrationId = 1, syncFailType = LinkDeviceSettingsState.SyncFailType.NOT_RETRYABLE ), seenQrEducationSheet = true @@ -724,7 +726,7 @@ private fun DeviceListScreenNotEnoughStoragePreview() { state = LinkDeviceSettingsState( dialogState = DialogState.SyncingFailed( deviceId = 1, - deviceCreatedAt = 1, + deviceRegistrationId = 1, syncFailType = LinkDeviceSettingsState.SyncFailType.NOT_ENOUGH_SPACE ), seenQrEducationSheet = true diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceRepository.kt index 16babcd275..484c650e26 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceRepository.kt @@ -8,6 +8,7 @@ import org.signal.core.util.logging.Log import org.signal.core.util.logging.logD import org.signal.core.util.logging.logI import org.signal.core.util.logging.logW +import org.signal.core.util.toByteArray import org.signal.libsignal.protocol.InvalidKeyException import org.signal.libsignal.protocol.ecc.ECPublicKey import org.thoughtcrime.securesms.backup.BackupFileIOError @@ -34,6 +35,7 @@ import java.io.File import java.io.FileInputStream import java.io.FileOutputStream import java.io.IOException +import java.nio.ByteBuffer import java.nio.charset.StandardCharsets import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds @@ -44,6 +46,7 @@ import kotlin.time.Duration.Companion.milliseconds object LinkDeviceRepository { private val TAG = Log.tag(LinkDeviceRepository::class) + private const val DECRYPTION_INFO = "deviceCreatedAt" fun removeDevice(deviceId: Int): Boolean { return when (val result = AppDependencies.linkDeviceApi.removeDevice(deviceId)) { @@ -75,18 +78,20 @@ object LinkDeviceRepository { } } - fun WaitForLinkedDeviceResponse.getPlaintextDeviceName(): String { + fun WaitForLinkedDeviceResponse.getPlaintextDevice(): Device { val response = this return DeviceInfo().apply { id = response.id name = response.name - created = response.created lastSeen = response.lastSeen - }.toDevice().name ?: "" + registrationId = response.registrationId + createdAtCiphertext = response.createdAtCiphertext + }.toDevice() } private fun DeviceInfo.toDevice(): Device { - val defaultDevice = Device(getId(), getName(), getCreated(), getLastSeen()) + val createdAt = this.getPlaintextCreatedAt() + val defaultDevice = Device(getId(), getName(), createdAt, getLastSeen(), getRegistrationId()) try { if (getName().isNullOrEmpty() || getName().length < 4) { Log.w(TAG, "Invalid DeviceInfo name.") @@ -105,13 +110,28 @@ object LinkDeviceRepository { return defaultDevice } - return Device(getId(), String(plaintext), getCreated(), getLastSeen()) + return Device(getId(), String(plaintext), createdAt, getLastSeen(), getRegistrationId()) } catch (e: Exception) { Log.w(TAG, "Failed while reading the protobuf.", e) } return defaultDevice } + private fun DeviceInfo.getPlaintextCreatedAt(): Long? { + return try { + val associatedData = byteArrayOf(getId().toByte()) + getRegistrationId().toByteArray() + val createdAtPlaintext = SignalStore.account.aciIdentityKey.privateKey.open( + ciphertext = Base64.decode(getCreatedAtCiphertext().toByteArray()), + info = DECRYPTION_INFO, + associatedData = associatedData + ) + ByteBuffer.wrap(createdAtPlaintext).getLong() + } catch (e: Exception) { + Log.w(TAG, "Failed while reading the protobuf.", e) + null + } + } + fun isValidQr(uri: Uri): Boolean { if (!uri.isHierarchical) { return false @@ -254,7 +274,7 @@ object LinkDeviceRepository { /** * Performs the entire process of creating and uploading an archive for a newly-linked device. */ - fun createAndUploadArchive(ephemeralMessageBackupKey: MessageBackupKey, deviceId: Int, deviceCreatedAt: Long, cancellationSignal: () -> Boolean): LinkUploadArchiveResult { + fun createAndUploadArchive(ephemeralMessageBackupKey: MessageBackupKey, deviceId: Int, deviceRegistrationId: Int, cancellationSignal: () -> Boolean): LinkUploadArchiveResult { Log.d(TAG, "[createAndUploadArchive] Beginning process.") val stopwatch = Stopwatch("link-archive") val tempBackupFile = BlobProvider.getInstance().forNonAutoEncryptingSingleSessionOnDisk(AppDependencies.application) @@ -283,7 +303,7 @@ object LinkDeviceRepository { if (cancellationSignal()) { Log.i(TAG, "[createAndUploadArchive] Backup was cancelled.") - sendTransferArchiveError(deviceId, deviceCreatedAt, TransferArchiveError.RELINK_REQUESTED) + sendTransferArchiveError(deviceId, deviceRegistrationId, TransferArchiveError.RELINK_REQUESTED) return LinkUploadArchiveResult.BackupCreationCancelled } @@ -308,7 +328,7 @@ object LinkDeviceRepository { if (cancellationSignal()) { Log.i(TAG, "[createAndUploadArchive] Backup was cancelled.") - sendTransferArchiveError(deviceId, deviceCreatedAt, TransferArchiveError.RELINK_REQUESTED) + sendTransferArchiveError(deviceId, deviceRegistrationId, TransferArchiveError.RELINK_REQUESTED) return LinkUploadArchiveResult.BackupCreationCancelled } @@ -322,7 +342,7 @@ object LinkDeviceRepository { if (cancellationSignal()) { Log.i(TAG, "[createAndUploadArchive] Backup was cancelled.") - sendTransferArchiveError(deviceId, deviceCreatedAt, TransferArchiveError.RELINK_REQUESTED) + sendTransferArchiveError(deviceId, deviceRegistrationId, TransferArchiveError.RELINK_REQUESTED) return LinkUploadArchiveResult.BackupCreationCancelled } @@ -336,7 +356,7 @@ object LinkDeviceRepository { if (cancellationSignal()) { Log.i(TAG, "[createAndUploadArchive] Backup was cancelled.") - sendTransferArchiveError(deviceId, deviceCreatedAt, TransferArchiveError.RELINK_REQUESTED) + sendTransferArchiveError(deviceId, deviceRegistrationId, TransferArchiveError.RELINK_REQUESTED) return LinkUploadArchiveResult.BackupCreationCancelled } @@ -344,7 +364,7 @@ object LinkDeviceRepository { val transferSetResult = NetworkResult.withRetry { SignalNetwork.linkDevice.setTransferArchive( destinationDeviceId = deviceId, - destinationDeviceCreated = deviceCreatedAt, + destinationDeviceRegistrationId = deviceRegistrationId, cdn = uploadForm.cdn, cdnKey = uploadForm.key ) @@ -402,10 +422,10 @@ object LinkDeviceRepository { /** * If [createAndUploadArchive] is cancelled or fails to upload an archive, alert the linked device of the failure and if the user will try again */ - fun sendTransferArchiveError(deviceId: Int, deviceCreatedAt: Long, error: TransferArchiveError) { + fun sendTransferArchiveError(deviceId: Int, deviceRegistrationId: Int, error: TransferArchiveError) { val archiveErrorResult = SignalNetwork.linkDevice.setTransferArchiveError( destinationDeviceId = deviceId, - destinationDeviceCreated = deviceCreatedAt, + destinationDeviceRegistrationId = deviceRegistrationId, error = error ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceSettingsState.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceSettingsState.kt index 88640cb41a..e87c9f9829 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceSettingsState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceSettingsState.kt @@ -27,9 +27,9 @@ data class LinkDeviceSettingsState( data object None : DialogState data object Linking : DialogState data object Unlinking : DialogState - data class SyncingMessages(val deviceId: Int, val deviceCreatedAt: Long) : DialogState + data class SyncingMessages(val deviceId: Int) : DialogState data object SyncingTimedOut : DialogState - data class SyncingFailed(val deviceId: Int, val deviceCreatedAt: Long, val syncFailType: SyncFailType) : DialogState + data class SyncingFailed(val deviceId: Int, val deviceRegistrationId: Int, val syncFailType: SyncFailType) : DialogState data class DeviceUnlinked(val deviceCreatedAt: Long) : DialogState data object LoadingDebugLog : DialogState data object ContactSupport : DialogState diff --git a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceViewModel.kt index 7715c6dd33..f2a43a5813 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/linkdevice/LinkDeviceViewModel.kt @@ -16,7 +16,7 @@ import org.thoughtcrime.securesms.jobs.LinkedDeviceInactiveCheckJob import org.thoughtcrime.securesms.jobs.NewLinkedDeviceNotificationJob import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.linkdevice.LinkDeviceRepository.LinkDeviceResult -import org.thoughtcrime.securesms.linkdevice.LinkDeviceRepository.getPlaintextDeviceName +import org.thoughtcrime.securesms.linkdevice.LinkDeviceRepository.getPlaintextDevice import org.thoughtcrime.securesms.linkdevice.LinkDeviceSettingsState.DialogState import org.thoughtcrime.securesms.linkdevice.LinkDeviceSettingsState.OneTimeEvent import org.thoughtcrime.securesms.linkdevice.LinkDeviceSettingsState.QrCodeState @@ -300,12 +300,12 @@ class LinkDeviceViewModel : ViewModel() { } Log.d(TAG, "[addDeviceWithSync] Found a linked device! Creating notification job.") - NewLinkedDeviceNotificationJob.enqueue(waitResult.id, waitResult.created) + NewLinkedDeviceNotificationJob.enqueue(waitResult.id, waitResult.getPlaintextDevice().createdMillis ?: System.currentTimeMillis()) _state.update { it.copy( linkDeviceResult = result, - dialogState = DialogState.SyncingMessages(waitResult.id, waitResult.created) + dialogState = DialogState.SyncingMessages(waitResult.id) ) } @@ -313,7 +313,7 @@ class LinkDeviceViewModel : ViewModel() { val uploadResult = LinkDeviceRepository.createAndUploadArchive( ephemeralMessageBackupKey = ephemeralMessageBackupKey, deviceId = waitResult.id, - deviceCreatedAt = waitResult.created, + deviceRegistrationId = waitResult.registrationId, cancellationSignal = { _state.value.shouldCancelArchiveUpload } ) @@ -323,7 +323,7 @@ class LinkDeviceViewModel : ViewModel() { Log.i(TAG, "[addDeviceWithSync] Successfully uploaded archive.") _state.update { it.copy( - oneTimeEvent = OneTimeEvent.ToastLinked(waitResult.getPlaintextDeviceName()), + oneTimeEvent = OneTimeEvent.ToastLinked(waitResult.getPlaintextDevice().name ?: ""), dialogState = DialogState.None ) } @@ -335,7 +335,7 @@ class LinkDeviceViewModel : ViewModel() { it.copy( dialogState = DialogState.SyncingFailed( deviceId = waitResult.id, - deviceCreatedAt = waitResult.created, + deviceRegistrationId = waitResult.registrationId, syncFailType = LinkDeviceSettingsState.SyncFailType.NOT_ENOUGH_SPACE ) ) @@ -347,7 +347,7 @@ class LinkDeviceViewModel : ViewModel() { it.copy( dialogState = DialogState.SyncingFailed( deviceId = waitResult.id, - deviceCreatedAt = waitResult.created, + deviceRegistrationId = waitResult.registrationId, syncFailType = LinkDeviceSettingsState.SyncFailType.NOT_RETRYABLE ) ) @@ -360,7 +360,7 @@ class LinkDeviceViewModel : ViewModel() { it.copy( dialogState = DialogState.SyncingFailed( deviceId = waitResult.id, - deviceCreatedAt = waitResult.created, + deviceRegistrationId = waitResult.registrationId, syncFailType = LinkDeviceSettingsState.SyncFailType.RETRYABLE ) ) @@ -404,9 +404,10 @@ class LinkDeviceViewModel : ViewModel() { Log.i(TAG, "No linked device found!") } else { Log.i(TAG, "Found a linked device! Creating notification job.") - NewLinkedDeviceNotificationJob.enqueue(waitResult.id, waitResult.created) + val device = waitResult.getPlaintextDevice() + NewLinkedDeviceNotificationJob.enqueue(waitResult.id, device.createdMillis ?: System.currentTimeMillis()) _state.update { - it.copy(oneTimeEvent = OneTimeEvent.ToastLinked(waitResult.getPlaintextDeviceName())) + it.copy(oneTimeEvent = OneTimeEvent.ToastLinked(device.name ?: "")) } } @@ -438,7 +439,7 @@ class LinkDeviceViewModel : ViewModel() { val dialogState = _state.value.dialogState if (dialogState is DialogState.SyncingFailed) { Log.i(TAG, "Alerting linked device of sync failure - will not retry") - LinkDeviceRepository.sendTransferArchiveError(dialogState.deviceId, dialogState.deviceCreatedAt, TransferArchiveError.CONTINUE_WITHOUT_UPLOAD) + LinkDeviceRepository.sendTransferArchiveError(dialogState.deviceId, dialogState.deviceRegistrationId, TransferArchiveError.CONTINUE_WITHOUT_UPLOAD) } loadDevices() @@ -462,7 +463,7 @@ class LinkDeviceViewModel : ViewModel() { val dialogState = _state.value.dialogState if (dialogState is DialogState.SyncingFailed) { Log.i(TAG, "Alerting linked device of sync failure - will retry") - LinkDeviceRepository.sendTransferArchiveError(dialogState.deviceId, dialogState.deviceCreatedAt, TransferArchiveError.RELINK_REQUESTED) + LinkDeviceRepository.sendTransferArchiveError(dialogState.deviceId, dialogState.deviceRegistrationId, TransferArchiveError.RELINK_REQUESTED) Log.i(TAG, "Need to unlink device first...") val success = LinkDeviceRepository.removeDevice(dialogState.deviceId) diff --git a/core-util-jvm/src/main/java/org/signal/core/util/IntExtensions.kt b/core-util-jvm/src/main/java/org/signal/core/util/IntExtensions.kt new file mode 100644 index 0000000000..9e42aa62d9 --- /dev/null +++ b/core-util-jvm/src/main/java/org/signal/core/util/IntExtensions.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2025 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.signal.core.util + +import java.nio.ByteBuffer + +/** + * Converts the integer into [ByteArray]. + */ +fun Int.toByteArray(): ByteArray { + return ByteBuffer + .allocate(Int.SIZE_BYTES) + .putInt(this) + .array() +} diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/link/LinkDeviceApi.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/link/LinkDeviceApi.kt index 6fd2049405..dba3b59a47 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/link/LinkDeviceApi.kt +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/link/LinkDeviceApi.kt @@ -166,10 +166,10 @@ class LinkDeviceApi( * - 422: Bad inputs. * - 429: Rate-limited. */ - fun setTransferArchive(destinationDeviceId: Int, destinationDeviceCreated: Long, cdn: Int, cdnKey: String): NetworkResult { + fun setTransferArchive(destinationDeviceId: Int, destinationDeviceRegistrationId: Int, cdn: Int, cdnKey: String): NetworkResult { val body = SetLinkedDeviceTransferArchiveRequest( destinationDeviceId = destinationDeviceId, - destinationDeviceCreated = destinationDeviceCreated, + destinationDeviceRegistrationId = destinationDeviceRegistrationId, transferArchive = SetLinkedDeviceTransferArchiveRequest.TransferArchive.CdnInfo( cdn = cdn, key = cdnKey @@ -189,10 +189,10 @@ class LinkDeviceApi( * - 422: Bad inputs. * - 429: Rate-limited. */ - fun setTransferArchiveError(destinationDeviceId: Int, destinationDeviceCreated: Long, error: TransferArchiveError): NetworkResult { + fun setTransferArchiveError(destinationDeviceId: Int, destinationDeviceRegistrationId: Int, error: TransferArchiveError): NetworkResult { val body = SetLinkedDeviceTransferArchiveRequest( destinationDeviceId = destinationDeviceId, - destinationDeviceCreated = destinationDeviceCreated, + destinationDeviceRegistrationId = destinationDeviceRegistrationId, transferArchive = SetLinkedDeviceTransferArchiveRequest.TransferArchive.Error(error) ) val request = WebSocketRequestMessage.put("/v1/devices/transfer_archive", body) diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/link/SetLinkedDeviceTransferArchiveRequest.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/link/SetLinkedDeviceTransferArchiveRequest.kt index 5d111b39d8..3ec4f59f88 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/link/SetLinkedDeviceTransferArchiveRequest.kt +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/link/SetLinkedDeviceTransferArchiveRequest.kt @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonProperty */ data class SetLinkedDeviceTransferArchiveRequest( @JsonProperty val destinationDeviceId: Int, - @JsonProperty val destinationDeviceCreated: Long, + @JsonProperty val destinationDeviceRegistrationId: Int, @JsonProperty val transferArchive: TransferArchive ) { sealed class TransferArchive { diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/link/WaitForLinkedDeviceResponse.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/link/WaitForLinkedDeviceResponse.kt index 6aef006489..57408788d4 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/link/WaitForLinkedDeviceResponse.kt +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/link/WaitForLinkedDeviceResponse.kt @@ -13,6 +13,7 @@ import com.fasterxml.jackson.annotation.JsonProperty data class WaitForLinkedDeviceResponse( @JsonProperty val id: Int, @JsonProperty val name: String, - @JsonProperty val created: Long, - @JsonProperty val lastSeen: Long + @JsonProperty val lastSeen: Long, + @JsonProperty val registrationId: Int, + @JsonProperty val createdAtCiphertext: String? ) diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceInfo.java b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceInfo.java index f81deb2cc1..5acd4edc23 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceInfo.java +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/messages/multidevice/DeviceInfo.java @@ -17,10 +17,13 @@ public class DeviceInfo { public String name; @JsonProperty - public long created; + public long lastSeen; @JsonProperty - public long lastSeen; + public int registrationId; + + @JsonProperty + public String createdAtCiphertext; public DeviceInfo() {} @@ -32,11 +35,15 @@ public class DeviceInfo { return name; } - public long getCreated() { - return created; - } - public long getLastSeen() { return lastSeen; } + + public int getRegistrationId() { + return registrationId; + } + + public String getCreatedAtCiphertext() { + return createdAtCiphertext; + } }