feat(backup): add uploadBackupSnapshot and deleteBackupSnapshot to FirebaseStorageDataSource

This commit is contained in:
null 2026-06-30 20:42:38 -05:00
parent 909d261b6c
commit 230e7f6201
1 changed files with 31 additions and 0 deletions

View File

@ -68,6 +68,37 @@ class FirebaseStorageDataSource @Inject constructor(
.addOnFailureListener { cont.resumeWithException(it) }
}
/**
* Uploads an already-encrypted conversation-backup snapshot under the uploader's OWN path and
* returns the tokenized download URL (recorded in the couple-gated backup manifest so the partner
* can fetch it). The bytes are couple-key ciphertext, so Storage holds nothing readable. Living
* under users/{uid}/ means the existing account-delete cleanup covers backups too.
*/
suspend fun uploadBackupSnapshot(uid: String, snapshotId: String, encryptedBytes: ByteArray): String =
suspendCancellableCoroutine { cont ->
if (!isOnline()) {
cont.resumeWithException(IOException("No internet connection"))
return@suspendCancellableCoroutine
}
val ref = storage.reference.child("users/$uid/backups/$snapshotId")
val metadata = StorageMetadata.Builder()
.setContentType("application/octet-stream")
.build()
ref.putBytes(encryptedBytes, metadata)
.continueWithTask { ref.downloadUrl }
.addOnSuccessListener { cont.resume(it.toString()) }
.addOnFailureListener { cont.resumeWithException(it) }
}
/** Best-effort delete of a previously-uploaded backup snapshot (post-compaction cleanup; succeeds
* only for the uploader's own path, so a cross-partner stale blob is left for that owner/cleanup). */
suspend fun deleteBackupSnapshot(uid: String, snapshotId: String): Unit =
suspendCancellableCoroutine { cont ->
storage.reference.child("users/$uid/backups/$snapshotId").delete()
.addOnSuccessListener { cont.resume(Unit) }
.addOnFailureListener { cont.resume(Unit) } // best-effort; a leftover blob is harmless ciphertext
}
/**
* Downloads the raw (still-encrypted) bytes for a media message over HTTP using the tokenized
* download URL, so the partner can read the author's object (the URL token authorizes it,