From 84c6719d036aa1c1cea05fede6f2e00b1d817ba0 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Fri, 18 Jul 2025 16:58:24 -0300 Subject: [PATCH] Attempt to heal if we have everything we need but no entitlement. --- .../thoughtcrime/securesms/database/InAppPaymentTable.kt | 6 ++++++ .../securesms/jobs/BackupSubscriptionCheckJob.kt | 9 +++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/InAppPaymentTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/InAppPaymentTable.kt index c971e2a500..e8fd8675ac 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/InAppPaymentTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/InAppPaymentTable.kt @@ -327,6 +327,12 @@ class InAppPaymentTable(context: Context, databaseHelper: SignalDatabase) : Data .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. */ diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupSubscriptionCheckJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupSubscriptionCheckJob.kt index 077e9af4e8..a55e2267d7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupSubscriptionCheckJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupSubscriptionCheckJob.kt @@ -152,7 +152,12 @@ class BackupSubscriptionCheckJob private constructor(parameters: Parameters) : C val hasTokenMismatch = purchaseToken?.let { hasLocalDevicePurchaseTokenMismatch(purchaseToken) } == true if (hasActiveSignalSubscription && hasTokenMismatch) { 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 return Result.success() } 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( subscriberType = InAppPaymentSubscriberRecord.Type.BACKUP, isRotation = true,