diff --git a/CRM/Stripe/PaymentIntent.php b/CRM/Stripe/PaymentIntent.php index 641a1842e51dcc970c3560a4405921b187d5905e..54c87f1cc8a255044f245822035f3c9fb0f6cd07 100644 --- a/CRM/Stripe/PaymentIntent.php +++ b/CRM/Stripe/PaymentIntent.php @@ -341,7 +341,6 @@ class CRM_Stripe_PaymentIntent { * * @return object * @throws \CRM_Core_Exception - * @throws \CiviCRM_API3_Exception * @throws \Stripe\Exception\ApiErrorException */ public function processIntent(array $params) { diff --git a/Civi/Api4/Action/StripePaymentintent/ProcessPublic.php b/Civi/Api4/Action/StripePaymentintent/ProcessPublic.php index dec6afc83a8b1038ea4f7c1af5343187d1647c50..dee3b13c4ee8462325ca04f605395ab51da93d24 100644 --- a/Civi/Api4/Action/StripePaymentintent/ProcessPublic.php +++ b/Civi/Api4/Action/StripePaymentintent/ProcessPublic.php @@ -12,6 +12,10 @@ namespace Civi\Api4\Action\StripePaymentintent; +use Brick\Math\RoundingMode; +use Brick\Money\Context\DefaultContext; +use Brick\Money\Money; + /** * Process a Stripe Intent with public/anonymous permissions * @@ -81,37 +85,40 @@ class ProcessPublic extends \Civi\Api4\Generic\AbstractAction { */ protected $csrfToken = ''; - /** - * @param \Civi\Api4\Generic\Result $result - * - * @return array - * @throws \CRM_Core_Exception - * @throws \CiviCRM_API3_Exception - */ /** * @param \Civi\Api4\Generic\Result $result * * @return void - * @throws \API_Exception * @throws \CRM_Core_Exception - * @throws \CiviCRM_API3_Exception * @throws \Stripe\Exception\ApiErrorException */ public function _run(\Civi\Api4\Generic\Result $result) { if (class_exists('\Civi\Firewall\Firewall')) { $firewall = new \Civi\Firewall\Firewall(); if (!$firewall->checkIsCSRFTokenValid(\CRM_Utils_Type::validate($this->csrfToken, 'String'))) { - throw new \API_Exception($firewall->getReasonDescription()); + throw new \CRM_Core_Exception($firewall->getReasonDescription()); } } if (empty($this->amount) && !$this->setup) { \Civi::log('stripe')->error(__CLASS__ . 'missing amount and not capture or setup'); - throw new \API_Exception('Bad request'); + throw new \CRM_Core_Exception('Bad request'); } + + // If we configured a minimum allowed amount for processing check it here + $minAmount = \Civi::settings()->get('stripe_minamount'); + if (!empty($minAmount)) { + $moneyAmount = Money::of($this->amount, $this->currency, new DefaultContext(), RoundingMode::CEILING); + $moneyMinAmount = Money::of($minAmount, $this->currency, new DefaultContext(), RoundingMode::CEILING); + if ($moneyAmount->isLessThan($moneyMinAmount)) { + \Civi::log('stripe')->error(__CLASS__ . 'amount: ' . $this->amount . ' is less than min_amount: ' . $minAmount); + throw new \CRM_Core_Exception('Bad request'); + } + } + if (empty($this->paymentProcessorID)) { \Civi::log('stripe')->error(__CLASS__ . ' missing paymentProcessorID'); - throw new \API_Exception('Bad request'); + throw new \CRM_Core_Exception('Bad request'); } $intentProcessor = new \CRM_Stripe_PaymentIntent(); @@ -135,7 +142,7 @@ class ProcessPublic extends \Civi\Api4\Generic\AbstractAction { $result->exchangeArray($processIntentResult->data); } else { - throw new \API_Exception($processIntentResult->message); + throw new \CRM_Core_Exception($processIntentResult->message); } } diff --git a/settings/stripe.setting.php b/settings/stripe.setting.php index a677cfa7f65f999d49e43f564fa67cf4ddccf1a2..ca3a97f3a725d2021cd0f8abb24a0391e334472b 100644 --- a/settings/stripe.setting.php +++ b/settings/stripe.setting.php @@ -222,4 +222,23 @@ Do NOT enable unless you\'ve enabled this feature on your Stripe account - see < ] ], ], + 'stripe_minamount' => [ + 'name' => 'stripe_minamount', + 'type' => 'Integer', + 'html_type' => 'text', + 'default' => 0, + 'is_domain' => 1, + 'is_contact' => 0, + 'title' => E::ts('Minimum amount that Stripe is allowed to process.'), + 'description' => E::ts('Default 0. This can help reduce the impact of card testing attacks as they tend to use low amounts eg. $1. If you know that your will never take payments under eg. $10 you can set that here and the request will fail for anything below that amount.'), + 'html_attributes' => [ + 'size' => 10, + 'maxlength' => 3, + ], + 'settings_pages' => [ + 'stripe' => [ + 'weight' => 120, + ] + ], + ], ];