feat(backup): pass recovery phrase through RestoreManager fulfill/complete (R24-c)

This commit is contained in:
null 2026-06-30 21:24:30 -05:00
parent 209ad74532
commit 71227561e7
1 changed files with 8 additions and 3 deletions

View File

@ -76,7 +76,7 @@ class RestoreManager @Inject constructor(
): Result<BackupRestoreManager.RestoreResult> = runCatching { ): Result<BackupRestoreManager.RestoreResult> = runCatching {
val keybox = request.keybox ?: error("no keybox yet") val keybox = request.keybox ?: error("no keybox yet")
val privateKey = userKeyManager.loadPrivateKey() ?: error("device key missing") val privateKey = userKeyManager.loadPrivateKey() ?: error("device key missing")
val keyset = coupleKeyTransfer.unwrapCoupleKey( val transferred = coupleKeyTransfer.unwrapCoupleKey(
keyboxB64 = keybox, keyboxB64 = keybox,
recipientPrivateKey = privateKey, recipientPrivateKey = privateKey,
coupleId = session.coupleId, coupleId = session.coupleId,
@ -84,7 +84,8 @@ class RestoreManager @Inject constructor(
recipientUid = session.recipientUid, recipientUid = session.recipientUid,
nonce = request.requestNonce nonce = request.requestNonce
) )
encryptionManager.storeTransferredKeyset(session.coupleId, keyset) // Store the key AND, if the partner included it, the couple's recovery phrase.
encryptionManager.storeTransferredKeyset(session.coupleId, transferred.keyset, transferred.recoveryPhrase)
// Consume the request so no wrapped couple key lingers server-side. // Consume the request so no wrapped couple key lingers server-side.
backupDataSource.deleteRestoreRequest(session.coupleId, session.recipientUid) backupDataSource.deleteRestoreRequest(session.coupleId, session.recipientUid)
backupRestoreManager.restore() backupRestoreManager.restore()
@ -106,13 +107,17 @@ class RestoreManager @Inject constructor(
val expected = CoupleKeyTransfer.verificationCode(request.recipientPublicKey, request.requestNonce) val expected = CoupleKeyTransfer.verificationCode(request.recipientPublicKey, request.requestNonce)
require(enteredCode.trim() == expected) { "verification code does not match" } require(enteredCode.trim() == expected) { "verification code does not match" }
val coupleKeyset = encryptionManager.exportKeysetForTransfer(coupleId) ?: error("couple key missing on this device") val coupleKeyset = encryptionManager.exportKeysetForTransfer(coupleId) ?: error("couple key missing on this device")
// Hand back the couple's recovery phrase too, if we have it, so the restored device isn't left
// without the self-recovery backstop. Null (we're phrase-less ourselves) → key-only, as before.
val recoveryPhrase = encryptionManager.recoveryPhrase(coupleId)
val keybox = coupleKeyTransfer.wrapCoupleKey( val keybox = coupleKeyTransfer.wrapCoupleKey(
coupleKeyset = coupleKeyset, coupleKeyset = coupleKeyset,
recipientPublicKeyB64 = request.recipientPublicKey, recipientPublicKeyB64 = request.recipientPublicKey,
coupleId = coupleId, coupleId = coupleId,
senderUid = uid, senderUid = uid,
recipientUid = recipientUid, recipientUid = recipientUid,
nonce = request.requestNonce nonce = request.requestNonce,
recoveryPhrase = recoveryPhrase
) )
// Make sure the partner can also pull fresh content right after unlocking the key. // Make sure the partner can also pull fresh content right after unlocking the key.
runCatching { backupManager.backupNow(force = true) } runCatching { backupManager.backupNow(force = true) }