mattrogowski
Well-known member
- Affected version
- 2.2.5
When a payment is received for a recurring user upgrade, but the user upgrade no longer exists, this is not gracefully handled and throws a
Full stack trace:
This has seemingly caused PayPal's IPN to be disabled on a client site due to repeated error responses to the IPN.
To reproduce (locally):
From what I can see,
An unexpected error occurred. Please try again later.
error with a 500 status, and the following error in the server error log:TypeError: Argument 2 passed to XF\Service\User\Upgrade::__construct() must be an instance of XF\Entity\UserUpgrade, null given, called in ~/src/XF/Container.php on line 270 src/XF/Service/User/Upgrade.php:32
Full stack trace:
Code:
#0 src/XF/Container.php(270): XF\Service\User\Upgrade->__construct(Object(XF\Pub\App), NULL, Object(XFMG\XF\Entity\User))
#1 src/XF/App.php(1701): XF\Container->createObject('XF\\Service\\User...', Array)
#2 src/XF/Container.php(228): XF\App->XF\{closure}('XF\\Service\\User...', Array, Object(XF\Container))
#3 src/XF/App.php(3002): XF\Container->create('service', 'XF:User\\Upgrade', Array)
#4 src/XF/Purchasable/UserUpgrade.php(140): XF\App->service('XF:User\\Upgrade', NULL, Object(XFMG\XF\Entity\User))
#5 src/XF/Payment/AbstractProvider.php(172): XF\Purchasable\UserUpgrade->completePurchase(Object(XF\Payment\CallbackState))
#6 payment_callback.php(63): XF\Payment\AbstractProvider->completeTransaction(Object(XF\Payment\CallbackState))
#7 /Users/mattrogowski/.composer/vendor/laravel/valet/server.php(219): require('/Users/mattrogo...')
#8 {main}
This has seemingly caused PayPal's IPN to be disabled on a client site due to repeated error responses to the IPN.
To reproduce (locally):
- Create a user upgrade
- Purchase the upgrade
- Delete the upgrade entirely
- Manually simulate the payment callback - I am using Postman for this
- You will need to get the request_key from xf_purchase_request and put this in the relevant field for the payment provider fake payload
- May also need to make hacky edits to the payment provider classes to force it to accept the fake request (bypass integrity checks)
- You should then get a response of
An unexpected error occurred. Please try again later.
and the server error will be logged
From what I can see,
XF\Payment\PayPal::validateTransaction()
has a check for if the upgrade exists on line 245, but only if $state->legacy
is true. However, XF\Purchasable\UserUpgrade::completePurchase()
tries to find a user upgrade on line 135 and assumes it finds one - if $state->legacy
is false, it uses $userUpgradeId
from line 128, and then doesn't handle not finding an upgrade.
Last edited: