Attempt to heal if we have everything we need but no entitlement.

This commit is contained in:
Alex Hart
2025-07-18 16:58:24 -03:00
committed by GitHub
parent e0df5e6df0
commit 84c6719d03
2 changed files with 13 additions and 2 deletions

View File

@@ -327,6 +327,12 @@ class InAppPaymentTable(context: Context, databaseHelper: SignalDatabase) : Data
.run() .run()
} }
fun hasPendingBackupRedemption(): Boolean {
return readableDatabase.exists(TABLE_NAME)
.where("$STATE = ? AND $TYPE = ?", State.serialize(State.PENDING), InAppPaymentType.serialize(InAppPaymentType.RECURRING_BACKUP))
.run()
}
/** /**
* Retrieves from the database the latest payment of the given type that is either in the PENDING or WAITING_FOR_AUTHORIZATION state. * Retrieves from the database the latest payment of the given type that is either in the PENDING or WAITING_FOR_AUTHORIZATION state.
*/ */

View File

@@ -152,7 +152,12 @@ class BackupSubscriptionCheckJob private constructor(parameters: Parameters) : C
val hasTokenMismatch = purchaseToken?.let { hasLocalDevicePurchaseTokenMismatch(purchaseToken) } == true val hasTokenMismatch = purchaseToken?.let { hasLocalDevicePurchaseTokenMismatch(purchaseToken) } == true
if (hasActiveSignalSubscription && hasTokenMismatch) { if (hasActiveSignalSubscription && hasTokenMismatch) {
Log.i(TAG, "Encountered token mismatch with an active Signal subscription. Attempting to redeem against latest token.", true) Log.i(TAG, "Encountered token mismatch with an active Signal subscription. Attempting to redeem against latest token.", true)
enqueueRedemptionForNewToken(purchaseToken, product.price) rotateAndRedeem(purchaseToken, product.price)
SignalStore.backup.subscriptionStateMismatchDetected = false
return Result.success()
} else if (purchaseToken != null && hasActiveSignalSubscription && !hasActivePaidBackupTier && !SignalDatabase.inAppPayments.hasPendingBackupRedemption()) {
Log.i(TAG, "We have an active signal subscription and active purchase, but no entitlement and no pending redemption. Enqueuing a redemption now.")
rotateAndRedeem(purchaseToken, product.price)
SignalStore.backup.subscriptionStateMismatchDetected = false SignalStore.backup.subscriptionStateMismatchDetected = false
return Result.success() return Result.success()
} else { } else {
@@ -203,7 +208,7 @@ class BackupSubscriptionCheckJob private constructor(parameters: Parameters) : C
} }
} }
private fun enqueueRedemptionForNewToken(localDevicePurchaseToken: String, localProductPrice: FiatMoney) { private fun rotateAndRedeem(localDevicePurchaseToken: String, localProductPrice: FiatMoney) {
RecurringInAppPaymentRepository.ensureSubscriberIdSync( RecurringInAppPaymentRepository.ensureSubscriberIdSync(
subscriberType = InAppPaymentSubscriberRecord.Type.BACKUP, subscriberType = InAppPaymentSubscriberRecord.Type.BACKUP,
isRotation = true, isRotation = true,