mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-26 12:44:38 +00:00
Update to the latest backup v2 spec.
Removes some dead protos, removes some sticker details, adds in gift badges.
This commit is contained in:
@@ -8,8 +8,6 @@ package org.thoughtcrime.securesms.backup.v2.database
|
||||
import android.database.Cursor
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.signal.core.util.Base64
|
||||
import org.signal.core.util.Base64.decode
|
||||
import org.signal.core.util.Base64.decodeOrThrow
|
||||
import org.signal.core.util.Hex
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.requireBlob
|
||||
@@ -59,6 +57,7 @@ import org.thoughtcrime.securesms.database.model.Mention
|
||||
import org.thoughtcrime.securesms.database.model.ReactionRecord
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.SessionSwitchoverEvent
|
||||
@@ -79,6 +78,7 @@ import java.util.LinkedList
|
||||
import java.util.Queue
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.BodyRange as BackupBodyRange
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GiftBadge as BackupGiftBadge
|
||||
|
||||
/**
|
||||
* An iterator for chat items with a clever performance twist: rather than do the extra queries one at a time (for reactions,
|
||||
@@ -173,7 +173,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
MessageTypes.isSessionSwitchoverType(record.type) -> {
|
||||
builder.updateMessage = ChatUpdateMessage(
|
||||
sessionSwitchover = try {
|
||||
val event = SessionSwitchoverEvent.ADAPTER.decode(decodeOrThrow(record.body!!))
|
||||
val event = SessionSwitchoverEvent.ADAPTER.decode(Base64.decodeOrThrow(record.body!!))
|
||||
SessionSwitchoverChatUpdate(event.e164.e164ToLong()!!)
|
||||
} catch (e: Exception) {
|
||||
SessionSwitchoverChatUpdate()
|
||||
@@ -183,7 +183,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
MessageTypes.isThreadMergeType(record.type) -> {
|
||||
builder.updateMessage = ChatUpdateMessage(
|
||||
threadMerge = try {
|
||||
val event = ThreadMergeEvent.ADAPTER.decode(decodeOrThrow(record.body!!))
|
||||
val event = ThreadMergeEvent.ADAPTER.decode(Base64.decodeOrThrow(record.body!!))
|
||||
ThreadMergeChatUpdate(event.previousE164.e164ToLong()!!)
|
||||
} catch (e: Exception) {
|
||||
ThreadMergeChatUpdate()
|
||||
@@ -198,7 +198,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
)
|
||||
} else if (record.body != null) {
|
||||
try {
|
||||
val decoded: ByteArray = decode(record.body)
|
||||
val decoded: ByteArray = Base64.decode(record.body)
|
||||
val context = DecryptedGroupV2Context.ADAPTER.decode(decoded)
|
||||
builder.updateMessage = ChatUpdateMessage(
|
||||
groupChange = GroupsV2UpdateMessageConverter.translateDecryptedChange(selfIds = SignalStore.account().getServiceIds(), context)
|
||||
@@ -347,6 +347,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
)
|
||||
}
|
||||
}
|
||||
MessageTypes.isGiftBadge(record.type) -> { builder.giftBadge = record.toBackupGiftBadge() }
|
||||
else -> {
|
||||
if (record.body == null && !attachmentsById.containsKey(record.id)) {
|
||||
Log.w(TAG, "Record missing a body and doesnt have attachments, skipping")
|
||||
@@ -479,6 +480,25 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
}
|
||||
}
|
||||
|
||||
private fun BackupMessageRecord.toBackupGiftBadge(): BackupGiftBadge {
|
||||
val giftBadge = try {
|
||||
GiftBadge.ADAPTER.decode(Base64.decode(this.body ?: ""))
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "Failed to decode GiftBadge!")
|
||||
return BackupGiftBadge()
|
||||
}
|
||||
|
||||
return BackupGiftBadge(
|
||||
receiptCredentialPresentation = giftBadge.redemptionToken,
|
||||
state = when (giftBadge.redemptionState) {
|
||||
GiftBadge.RedemptionState.REDEEMED -> BackupGiftBadge.State.REDEEMED
|
||||
GiftBadge.RedemptionState.FAILED -> BackupGiftBadge.State.FAILED
|
||||
GiftBadge.RedemptionState.PENDING -> BackupGiftBadge.State.UNOPENED
|
||||
GiftBadge.RedemptionState.STARTED -> BackupGiftBadge.State.OPENED
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<DatabaseAttachment>.toBackupQuoteAttachments(): List<Quote.QuotedAttachment> {
|
||||
return this.map { attachment ->
|
||||
Quote.QuotedAttachment(
|
||||
@@ -507,7 +527,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
builder.backupLocator = FilePointer.BackupLocator(
|
||||
mediaName = archiveMediaName ?: this.getMediaName().toString(),
|
||||
cdnNumber = if (archiveMediaName != null) archiveCdn else Cdn.CDN_3.cdnNumber, // TODO (clark): Update when new proto with optional cdn is landed
|
||||
key = decode(remoteKey).toByteString(),
|
||||
key = Base64.decode(remoteKey).toByteString(),
|
||||
size = this.size.toInt(),
|
||||
digest = remoteDigest.toByteString()
|
||||
)
|
||||
@@ -519,7 +539,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
cdnKey = this.remoteLocation,
|
||||
cdnNumber = this.cdn.cdnNumber,
|
||||
uploadTimestamp = this.uploadTimestamp,
|
||||
key = decode(remoteKey).toByteString(),
|
||||
key = Base64.decode(remoteKey).toByteString(),
|
||||
size = this.size.toInt(),
|
||||
digest = remoteDigest.toByteString()
|
||||
)
|
||||
@@ -538,7 +558,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
} else {
|
||||
MessageAttachment.Flag.NONE
|
||||
},
|
||||
uuid = uuid?.let { UuidUtil.toByteString(uuid) }
|
||||
clientUuid = uuid?.let { UuidUtil.toByteString(uuid) }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ import org.thoughtcrime.securesms.database.model.Mention
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.CryptoValue
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GV2UpdateDescription
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.PaymentTombstone
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ProfileChangeDetails
|
||||
@@ -77,6 +78,7 @@ import org.whispersystems.signalservice.internal.push.DataMessage
|
||||
import java.math.BigInteger
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GiftBadge as BackupGiftBadge
|
||||
|
||||
/**
|
||||
* An object that will ingest all fo the [ChatItem]s you want to write, buffer them until hitting a specified batch size, and then batch insert them
|
||||
@@ -410,6 +412,7 @@ class ChatItemImportInserter(
|
||||
this.remoteDeletedMessage != null -> contentValues.put(MessageTable.REMOTE_DELETED, 1)
|
||||
this.updateMessage != null -> contentValues.addUpdateMessage(this.updateMessage)
|
||||
this.paymentNotification != null -> contentValues.addPaymentNotification(this, chatRecipientId)
|
||||
this.giftBadge != null -> contentValues.addGiftBadge(this.giftBadge)
|
||||
}
|
||||
|
||||
return contentValues
|
||||
@@ -517,6 +520,10 @@ class ChatItemImportInserter(
|
||||
type = type or MessageTypes.SECURE_MESSAGE_BIT or MessageTypes.PUSH_MESSAGE_BIT
|
||||
}
|
||||
|
||||
if (this.giftBadge != null) {
|
||||
type = type or MessageTypes.SPECIAL_TYPE_GIFT_BADGE
|
||||
}
|
||||
|
||||
return type
|
||||
}
|
||||
|
||||
@@ -695,6 +702,20 @@ class ChatItemImportInserter(
|
||||
)
|
||||
}
|
||||
|
||||
private fun ContentValues.addGiftBadge(giftBadge: BackupGiftBadge) {
|
||||
val dbGiftBadge = GiftBadge(
|
||||
redemptionToken = giftBadge.receiptCredentialPresentation,
|
||||
redemptionState = when (giftBadge.state) {
|
||||
BackupGiftBadge.State.UNOPENED -> GiftBadge.RedemptionState.PENDING
|
||||
BackupGiftBadge.State.OPENED -> GiftBadge.RedemptionState.STARTED
|
||||
BackupGiftBadge.State.REDEEMED -> GiftBadge.RedemptionState.REDEEMED
|
||||
BackupGiftBadge.State.FAILED -> GiftBadge.RedemptionState.FAILED
|
||||
}
|
||||
)
|
||||
|
||||
put(MessageTable.BODY, Base64.encodeWithPadding(GiftBadge.ADAPTER.encode(dbGiftBadge)))
|
||||
}
|
||||
|
||||
private fun String?.tryParseMoney(): Money? {
|
||||
if (this.isNullOrEmpty()) {
|
||||
return null
|
||||
@@ -915,7 +936,7 @@ class ChatItemImportInserter(
|
||||
gif = flag == MessageAttachment.Flag.GIF,
|
||||
borderless = flag == MessageAttachment.Flag.BORDERLESS,
|
||||
wasDownloaded = wasDownloaded,
|
||||
uuid = uuid
|
||||
uuid = clientUuid
|
||||
)
|
||||
}
|
||||
|
||||
@@ -927,7 +948,7 @@ class ChatItemImportInserter(
|
||||
wasDownloaded = wasDownloaded,
|
||||
contentType = contentType,
|
||||
fileName = fileName,
|
||||
uuid = uuid
|
||||
uuid = clientUuid
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,18 +5,14 @@
|
||||
|
||||
package org.thoughtcrime.securesms.backup.v2.processor
|
||||
|
||||
import androidx.annotation.WorkerThread
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.signal.core.util.Hex
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.Frame
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.StickerPack
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.StickerPackSticker
|
||||
import org.thoughtcrime.securesms.backup.v2.stream.BackupFrameEmitter
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.StickerTable.StickerPackRecordReader
|
||||
import org.thoughtcrime.securesms.database.StickerTable.StickerRecordReader
|
||||
import org.thoughtcrime.securesms.database.model.StickerPackRecord
|
||||
import org.thoughtcrime.securesms.database.model.StickerRecord
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob
|
||||
|
||||
@@ -41,36 +37,12 @@ object StickerBackupProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun getStickersFromDatabase(packId: String): List<StickerPackSticker> {
|
||||
val stickers: MutableList<StickerPackSticker> = java.util.ArrayList()
|
||||
|
||||
SignalDatabase.stickers.getStickersForPack(packId).use { cursor ->
|
||||
val reader = StickerRecordReader(cursor)
|
||||
var record: StickerRecord? = reader.next
|
||||
while (record != null) {
|
||||
stickers.add(
|
||||
StickerPackSticker(
|
||||
emoji = record.emoji,
|
||||
id = record.stickerId
|
||||
)
|
||||
)
|
||||
record = reader.next
|
||||
}
|
||||
}
|
||||
return stickers
|
||||
}
|
||||
|
||||
private fun StickerPackRecord.toBackupFrame(): Frame {
|
||||
val packIdBytes = Hex.fromStringCondensed(packId)
|
||||
val packKey = Hex.fromStringCondensed(packKey)
|
||||
val stickers = getStickersFromDatabase(packId)
|
||||
val pack = StickerPack(
|
||||
packId = packIdBytes.toByteString(),
|
||||
packKey = packKey.toByteString(),
|
||||
title = title.orElse(""),
|
||||
author = author.orElse(""),
|
||||
stickers = stickers
|
||||
packKey = packKey.toByteString()
|
||||
)
|
||||
return Frame(stickerPack = pack)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user