From 9a40674d8d3224736e5737908131aef3c77c8f41 Mon Sep 17 00:00:00 2001 From: Phillip Thelen Date: Fri, 21 Oct 2022 16:57:12 +0200 Subject: [PATCH] Allow sub upgrades/downgrades on iOS --- website/server/libs/payments/apple.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/website/server/libs/payments/apple.js b/website/server/libs/payments/apple.js index bc99889587..5e688578d4 100644 --- a/website/server/libs/payments/apple.js +++ b/website/server/libs/payments/apple.js @@ -75,10 +75,6 @@ api.verifyPurchase = async function verifyPurchase (options) { }; api.subscribe = async function subscribe (sku, user, receipt, headers, nextPaymentProcessing) { - if (user && user.isSubscribed()) { - throw new NotAuthorized(this.constants.RESPONSE_ALREADY_USED); - } - if (!sku) throw new BadRequest(shared.i18n.t('missingSubscriptionCode')); let subCode; @@ -109,27 +105,34 @@ api.subscribe = async function subscribe (sku, user, receipt, headers, nextPayme throw new NotAuthorized(api.constants.RESPONSE_NO_ITEM_PURCHASED); } - let transactionId; + let originalTransactionId; + let newTransactionId; for (const purchaseData of purchaseDataList) { const dateTerminated = new Date(Number(purchaseData.expirationDate)); if (purchaseData.productId === sku && dateTerminated > new Date()) { - transactionId = purchaseData.transactionId; + originalTransactionId = purchaseData.originalTransactionId; + newTransactionId = purchaseData.transactionId; break; } } - if (transactionId) { + if (originalTransactionId) { + if (user && user.purchased.plan.customId !== originalTransactionId) { + throw new NotAuthorized(this.constants.RESPONSE_ALREADY_USED); + } const existingUser = await User.findOne({ - 'purchased.plan.customerId': transactionId, + 'purchased.plan.customerId': originalTransactionId, }).exec(); - if (existingUser) throw new NotAuthorized(this.constants.RESPONSE_ALREADY_USED); + if (existingUser && (originalTransactionId === newTransactionId || existingUser._id !== user._id)) { + throw new NotAuthorized(this.constants.RESPONSE_ALREADY_USED); + } nextPaymentProcessing = nextPaymentProcessing || moment.utc().add({ days: 2 }); // eslint-disable-line max-len, no-param-reassign await payments.createSubscription({ user, - customerId: transactionId, + customerId: originalTransactionId, paymentMethod: this.constants.PAYMENT_METHOD_APPLE, sub, headers,