CVE-2022-0689: Other (NVD-CWE-Other)
value: Use multiple time the one-time coupon in Packagist microweber/microweber prior to 1.2.11.
CWE description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
CVSS v3 base score: 5.3
Published: 2022-02-19T16:15Z
Repository: https://github.com/microweber/microweber
Language: PHP
Files changed: src/MicroweberPackages/Cart/CartManager.php, src/MicroweberPackages/Checkout/CheckoutManager.php, userfiles/modules/shop/coupons/functions.php
Commit date: 2022-02-19 17:43:46 +0200
Commit message: update

Diff: diff --git a/src/MicroweberPackages/Cart/CartManager.php b/src/MicroweberPackages/Cart/CartManager.php
index 92399a9525d..2b2ff36eab9 100644
--- a/src/MicroweberPackages/Cart/CartManager.php
+++ b/src/MicroweberPackages/Cart/CartManager.php
@@ -28,22 +28,21 @@ class CartManager extends Crud
             $this->app = $app;
         } else {
             $this->app = mw();
         }
 
-        $coupon_code = $this->app->user_manager->session_get('coupon_code');
-        $this->coupon_data = coupon_get_by_code($coupon_code);
+
     }
 
     /**
      * This will sum all cart items amount
      * @param bool $return_amount
      * @return array|false|float|int|mixed
      */
     public function sum($return_amount = true)
     {
-        if($return_amount ){
+        if ($return_amount) {
             return $this->app->cart_repository->getCartAmount();
         } else {
             return $this->app->cart_repository->getCartItemsCount();
         }
 
@@ -180,30 +179,49 @@ class CartManager extends Crud
         return $this->get_discount_value();
     }
 
     public function get_discount_type()
     {
-        if (empty($this->coupon_data)) {
+        $data = $this->couponCodeGetDataFromSession();
+        if (empty($data)) {
             return false;
         }
+        if (isset($data['discount_type'])) {
+            return $data['discount_type'];
+        }
+        return false;
+    }
 
-        return  $this->coupon_data['discount_type'];
+    public function set_coupon_data($data)
+    {
+        $this->coupon_data = $data;
     }
 
     public function get_discount_value()
     {
-        if (empty($this->coupon_data)) {
+        $data = $this->couponCodeGetDataFromSession();
+
+
+        if (empty($data)) {
+            return false;
+        }
+
+        if (!isset($data['discount_value'])) {
+            return false;
+        }
+
+        if (!isset($data['total_amount'])) {
             return false;
         }
 
         $apply_code = false;
-        if ($this->sum() >= $this->coupon_data['total_amount']) {
+        if ($this->sum() >= $data['total_amount']) {
             $apply_code = true;
         }
 
         if ($apply_code) {
-            return floatval($this->coupon_data['discount_value']);
+            return floatval($data['discount_value']);
         }
 
         return false;
     }
 
@@ -351,13 +369,13 @@ class CartManager extends Crud
         }
 
         $cart = array();
         $cart['id'] = intval($data['id']);
 
-       // if ($this->app->user_manager->is_admin() == false) {
+        // if ($this->app->user_manager->is_admin() == false) {
         $cart['session_id'] = mw()->user_manager->session_id();
-       // }
+        // }
 
         $cart['order_completed'] = 0;
         $cart['one'] = 1;
         $cart['limit'] = 1;
 
@@ -572,13 +590,13 @@ class CartManager extends Crud
         $prices = array();
 
         $skip_keys = array();
 
         $content_custom_fields = $this->app->fields_manager->get([
-            'rel_type'=>$for,
-            'rel_id'=>$for_id,
-            'return_full'=>true,
+            'rel_type' => $for,
+            'rel_id' => $for_id,
+            'return_full' => true,
         ]);
 
         $product_prices = array();
         if ($for == 'content') {
             $prices_data = app()->shop_manager->get_product_prices($for_id, true);
@@ -736,11 +754,11 @@ class CartManager extends Crud
                         $cart['qty'] = $check_cart['qty'] + $update_qty;
                     } elseif ($update_qty_new > 0) {
                         $cart['qty'] = $update_qty_new;
                     } else {
                         $cart['qty'] = $check_cart['qty'] + 1;
-                     }
+                    }
                 }
             } else {
                 if ($update_qty > 0) {
                     $cart['qty'] = $update_qty;
                 } else {
@@ -909,18 +927,56 @@ class CartManager extends Crud
     {
 
         $item = content_data($content_id);
         $isInStock = true;
         if ($item) {
-                if (isset($item['qty']) and $item['qty'] != 'nolimit' ) {
-                    $quantity =intval( $item['qty']);
-                    if ($quantity < 1) {
-                        $isInStock = false;
-                    }
+            if (isset($item['qty']) and $item['qty'] != 'nolimit') {
+                $quantity = intval($item['qty']);
+                if ($quantity < 1) {
+                    $isInStock = false;
                 }
+            }
 
         }
 
         return $isInStock;
     }
 
+    public function couponCodeGetDataFromSession()
+    {
+        $coupon_code = $this->app->user_manager->session_get('coupon_code');
+        if ($coupon_code and !$this->couponCodeCheckIfValid($coupon_code)) {
+            //check if coupon is valid
+            if (function_exists('coupons_delete_session')) {
+                coupons_delete_session();
+            }
+
+            $this->coupon_data = false;
+        } else {
+            if (function_exists('coupon_get_by_code')) {
+                $this->coupon_data = coupon_get_by_code($coupon_code);
+            } else {
+                $this->coupon_data = false;
+            }
+        }
+        return $this->coupon_data;
+    }
+
+    public function couponCodeCheckIfValid($coupon_code)
+    {
+        if (function_exists('coupon_apply')) {
+            //check if coupon is valid
+            $coupon_valid = coupon_apply([
+                'coupon_code' => $coupon_code,
+                'coupon_check_if_valid' => true
+            ]);
+            if (!$coupon_valid) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+
+    }
+
+
 }
diff --git a/src/MicroweberPackages/Checkout/CheckoutManager.php b/src/MicroweberPackages/Checkout/CheckoutManager.php
index 44647ceb797..321510134f0 100644
--- a/src/MicroweberPackages/Checkout/CheckoutManager.php
+++ b/src/MicroweberPackages/Checkout/CheckoutManager.php
@@ -432,10 +432,36 @@ class CheckoutManager
                     $place_order[$value] = $data[$value];
                     $posted_fields[$value] = $data[$value];
                 }
             }
 
+
+            // Discount details save
+            if ($coupon_code) {
+                $place_order['promo_code'] = $coupon_code;
+                $place_order['coupon_id'] = $coupon_id;
+                $place_order['discount_type'] = $discount_type;
+                $place_order['discount_value'] = $discount_value;
+
+
+                if (!$this->app->cart_manager->couponCodeCheckIfValid($coupon_code)) {
+                    //check if coupon is valid
+                    if(function_exists('coupons_delete_session')){
+                        coupons_delete_session();
+                    }
+
+                    $place_order['promo_code'] = '';
+                    $place_order['coupon_id'] ='';
+                    $place_order['discount_type'] = '';
+                    $place_order['discount_value'] ='';
+                }
+            }
+
+
+
+
+
             $amount = $this->app->shop_manager->cart_total();
             $tax = $this->app->cart_manager->get_tax();
 
 
             if (!empty($checkout_errors)) {
@@ -496,15 +522,10 @@ class CheckoutManager
             } else {
                 $place_order['item_name'] = 'Order id:' . ' ' . $place_order['id'];
             }
 
 
-            // Discount details save
-            $place_order['promo_code'] = $coupon_code;
-            $place_order['coupon_id'] = $coupon_id;
-            $place_order['discount_type'] = $discount_type;
-            $place_order['discount_value'] = $discount_value;
 
 
             // convert currency to payment provider currency
             $currencies_list_paypal = mw()->shop_manager->currency_get_for_paypal();
             $currencyCode = strtoupper($place_order['currency']);
@@ -1424,6 +1445,8 @@ class CheckoutManager
             ) : '') .
             (isset($e['path']) ? $e['path'] : '/') .
             (isset($e['query']) ? '?' . (is_array($e['query']) ? http_build_query($e['query'], '', '&') : $e['query']) : '') .
             (isset($e['fragment']) ? "#$e[fragment]" : '');
     }
+
+
 }
diff --git a/userfiles/modules/shop/coupons/functions.php b/userfiles/modules/shop/coupons/functions.php
index 6c4e50607b2..f0f1227f02f 100644
--- a/userfiles/modules/shop/coupons/functions.php
+++ b/userfiles/modules/shop/coupons/functions.php
@@ -25,18 +25,24 @@ function coupon_apply($params = array())
         return $json;
     }
 
     $customer_ip = user_ip();
 
-    $checkout = new MicroweberPackages\Checkout\CheckoutManager();
-    $getCart = $checkout->app->shop_manager->get_cart(array(
-        'session_id' => $checkout->app->user_manager->session_id()
-
-    ));
+//    $checkout = new MicroweberPackages\Checkout\CheckoutManager();
+//    $getCart = $checkout->app->shop_manager->get_cart(array(
+//        'session_id' => $checkout->app->user_manager->session_id()
+//
+//    ));
 
+    $getCart = false;
     $coupon['total_amount'] = floatval($coupon['total_amount']);
-    $cartTotal = floatval(cart_total());
+    $cartTotal = floatval( \DB::table('cart')->where('session_id', app()->user_manager->session_id())->sum('price'));
+    $getCartItems =   \DB::table('cart')->where('session_id', app()->user_manager->session_id())->get();
+
+    if($getCartItems){
+        $getCart = $getCartItems->toArray();
+    }
 
     // Check rules
      if ($coupon and isset($coupon['uses_per_customer']) and $coupon['uses_per_customer'] > 0) {
         $getLog = coupon_log_get_by_code_and_customer_ip($coupon_code, $customer_ip);
 
@@ -63,10 +69,15 @@ function coupon_apply($params = array())
 
     if (empty($errorMessage)) {
         $ok = true;
     }
 
+    if(isset( $params['coupon_check_if_valid'])){
+       return $ok;
+    }
+
+
     if ($ok) {
 
         mw()->user_manager->session_set('coupon_code', $coupon['coupon_code']);
         mw()->user_manager->session_set('coupon_id', $coupon['id']);
         mw()->user_manager->session_set('discount_value', $coupon['discount_value']);
@@ -292,10 +303,11 @@ function coupons_delete_session()
 {
     mw()->user_manager->session_del('coupon_code');
     mw()->user_manager->session_del('coupon_id');
     mw()->user_manager->session_del('discount_value');
     mw()->user_manager->session_del('discount_type');
+    mw()->user_manager->session_del('applied_coupon_data');
 }
 
 
 event_bind('mw.admin.shop.settings.menu', function ($data) {
     print '<div class="col-12 col-sm-6 col-lg-4">

Vulnerable code:         $coupon_code = $this->app->user_manager->session_get('coupon_code');
        $this->coupon_data = coupon_get_by_code($coupon_code);
        if($return_amount ){
        if (empty($this->coupon_data)) {
        return  $this->coupon_data['discount_type'];
        if (empty($this->coupon_data)) {
        if ($this->sum() >= $this->coupon_data['total_amount']) {
            return floatval($this->coupon_data['discount_value']);
       // if ($this->app->user_manager->is_admin() == false) {
       // }
            'rel_type'=>$for,
            'rel_id'=>$for_id,
            'return_full'=>true,
                     }
                if (isset($item['qty']) and $item['qty'] != 'nolimit' ) {
                    $quantity =intval( $item['qty']);
                    if ($quantity < 1) {
                        $isInStock = false;
                    }
            // Discount details save
            $place_order['promo_code'] = $coupon_code;
            $place_order['coupon_id'] = $coupon_id;
            $place_order['discount_type'] = $discount_type;
            $place_order['discount_value'] = $discount_value;
    $checkout = new MicroweberPackages\Checkout\CheckoutManager();
    $getCart = $checkout->app->shop_manager->get_cart(array(
        'session_id' => $checkout->app->user_manager->session_id()

    ));
    $cartTotal = floatval(cart_total());
Fixed code: 
        if ($return_amount) {
        $data = $this->couponCodeGetDataFromSession();
        if (empty($data)) {
        if (isset($data['discount_type'])) {
            return $data['discount_type'];
        }
        return false;
    }
    public function set_coupon_data($data)
    {
        $this->coupon_data = $data;
        $data = $this->couponCodeGetDataFromSession();


        if (empty($data)) {
            return false;
        }

        if (!isset($data['discount_value'])) {
            return false;
        }

        if (!isset($data['total_amount'])) {
        if ($this->sum() >= $data['total_amount']) {
            return floatval($data['discount_value']);
        // if ($this->app->user_manager->is_admin() == false) {
        // }
            'rel_type' => $for,
            'rel_id' => $for_id,
            'return_full' => true,
                    }
            if (isset($item['qty']) and $item['qty'] != 'nolimit') {
                $quantity = intval($item['qty']);
                if ($quantity < 1) {
                    $isInStock = false;
            }
    public function couponCodeGetDataFromSession()
    {
        $coupon_code = $this->app->user_manager->session_get('coupon_code');
        if ($coupon_code and !$this->couponCodeCheckIfValid($coupon_code)) {
            //check if coupon is valid
            if (function_exists('coupons_delete_session')) {
                coupons_delete_session();
            }

            $this->coupon_data = false;
        } else {
            if (function_exists('coupon_get_by_code')) {
                $this->coupon_data = coupon_get_by_code($coupon_code);
            } else {
                $this->coupon_data = false;
            }
        }
        return $this->coupon_data;
    }

    public function couponCodeCheckIfValid($coupon_code)
    {
        if (function_exists('coupon_apply')) {
            //check if coupon is valid
            $coupon_valid = coupon_apply([
                'coupon_code' => $coupon_code,
                'coupon_check_if_valid' => true
            ]);
            if (!$coupon_valid) {
                return false;
            }
            return true;
        }
        return false;

    }



            // Discount details save
            if ($coupon_code) {
                $place_order['promo_code'] = $coupon_code;
                $place_order['coupon_id'] = $coupon_id;
                $place_order['discount_type'] = $discount_type;
                $place_order['discount_value'] = $discount_value;


                if (!$this->app->cart_manager->couponCodeCheckIfValid($coupon_code)) {
                    //check if coupon is valid
                    if(function_exists('coupons_delete_session')){
                        coupons_delete_session();
                    }

                    $place_order['promo_code'] = '';
                    $place_order['coupon_id'] ='';
                    $place_order['discount_type'] = '';
                    $place_order['discount_value'] ='';
                }
            }







//    $checkout = new MicroweberPackages\Checkout\CheckoutManager();
//    $getCart = $checkout->app->shop_manager->get_cart(array(
//        'session_id' => $checkout->app->user_manager->session_id()
//
//    ));
    $getCart = false;
    $cartTotal = floatval( \DB::table('cart')->where('session_id', app()->user_manager->session_id())->sum('price'));
    $getCartItems =   \DB::table('cart')->where('session_id', app()->user_manager->session_id())->get();

    if($getCartItems){
        $getCart = $getCartItems->toArray();
    }
    if(isset( $params['coupon_check_if_valid'])){
       return $ok;
    }


    mw()->user_manager->session_del('applied_coupon_data');