From a3f0f08491140b962ce868b08856d4159f291f59 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Tue, 11 Aug 2026 16:59:14 -0300 Subject: [PATCH] Fully allow donations from linked devices. --- .../jobs/InAppPaymentRecurringContextJob.kt | 4 +-- .../InAppPaymentRecurringContextJobTest.kt | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJob.kt index 62ec7ced9d..fbb330a0dd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJob.kt @@ -154,9 +154,9 @@ class InAppPaymentRecurringContextJob private constructor( throw Exception("Unregistered users cannot perform this job.") } - if (SignalStore.account.isLinkedDevice) { + if (SignalStore.account.isLinkedDevice && SignalDatabase.inAppPayments.getById(inAppPaymentId)?.type == InAppPaymentType.RECURRING_BACKUP) { warning("Linked device. Failing.") - throw Exception("Linked devices cannot not perform this job") + throw Exception("Linked devices cannot perform this job for backups") } val (inAppPayment, requestContext) = getAndValidateInAppPayment() diff --git a/app/src/test/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJobTest.kt b/app/src/test/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJobTest.kt index fe04f69f72..3d325482ba 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJobTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/jobs/InAppPaymentRecurringContextJobTest.kt @@ -171,6 +171,37 @@ class InAppPaymentRecurringContextJobTest { assertThat(result.isSuccess).isTrue() } + @Test + fun `Given a linked device, when I run for a donation, then I expect success`() { + every { mockSignalStore.account.isLinkedDevice } returns true + + val activeSubscription = inAppPaymentsTestRule.createActiveSubscription() + inAppPaymentsTestRule.initializeActiveSubscriptionMock(activeSubscription = activeSubscription) + + val iap = insertInAppPayment() + val job = InAppPaymentRecurringContextJob.create(iap) + job.onAdded() + + val result = job.run() + assertThat(result.isSuccess).isTrue() + } + + @Test + fun `Given a linked device, when I run for a backup, then I expect failure`() { + every { mockSignalStore.account.isLinkedDevice } returns true + + val activeSubscription = inAppPaymentsTestRule.createActiveSubscription() + inAppPaymentsTestRule.initializeActiveSubscriptionMock(activeSubscription = activeSubscription) + + val iap = insertInAppPayment(type = InAppPaymentType.RECURRING_BACKUP) + val job = InAppPaymentRecurringContextJob.create(iap) + job.onAdded() + + val result = job.run() + assertThat(result.isFailure).isTrue() + verify(atLeast = 0, atMost = 0) { AppDependencies.donationsService.submitReceiptCredentialRequestSync(any(), any()) } + } + @Test fun `Given END state, when I run, then I expect failure`() { val iap = insertInAppPayment(