PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / trunk
WCPOS – Point of Sale (POS) plugin for WooCommerce vtrunk
1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 1.9.13 1.9.12 1.9.11 1.9.10 1.9.9 All 158 releases
woocommerce-pos / includes / Form_Handler.php

Form_Handler.php in WCPOS – Point of Sale (POS) plugin for WooCommerce trunk, at includes/Form_Handler.php

170 lines 5.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Form Handler.
4 *
5 * @package WCPOS\WooCommercePOS
6 */
7
8 namespace WCPOS\WooCommercePOS;
9
10 use WCPOS\WooCommercePOS\Services\Auth as AuthService;
11
12 /**
13 * Form_Handler class.
14 */
15 class Form_Handler {
16
17 /**
18 * Constructor.
19 */
20 public function __construct() {
21 // May need $wp global to access query vars.
22 add_action( 'wp', array( $this, 'pay_action' ), 10 );
23 add_action( 'wp', array( $this, 'coupon_action' ), 10 );
24 }
25
26 /**
27 * Hook in methods.
28 */
29 public static function init() {
30 // May need $wp global to access query vars.
31 add_action( 'wp', array( __CLASS__, 'pay_action' ), 10 );
32 }
33
34 /**
35 * Process the pay action.
36 *
37 * There's a problem if the woocommerce_pay nonce doesn't match the current user,
38 * so we need to check the order and set current user to the order's customer.
39 */
40 public function pay_action() {
41 global $wp;
42
43 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified by WooCommerce in the pay form handler.
44 if ( woocommerce_pos_request() && isset( $_POST['woocommerce_pay'], $_GET['key'] ) ) {
45 $order_id = absint( $wp->query_vars['order-pay'] );
46 $order = wc_get_order( $order_id );
47
48 // Ensure the order exists.
49 if ( ! $order ) {
50 wp_die(
51 /* translators: Checkout/payment form error message shown when the order cannot be found. */
52 esc_html__( 'Order does not exist.', 'woocommerce-pos' ),
53 /* translators: Checkout/payment form error message title. */
54 esc_html__( 'Error', 'woocommerce-pos' ),
55 array( 'response' => 403 )
56 );
57 }
58
59 // Verify the order key matches the key provided in the URL.
60 $provided_key = sanitize_text_field( wp_unslash( $_GET['key'] ) );
61 if ( $provided_key !== $order->get_order_key() ) {
62 wp_die(
63 /* translators: Checkout/payment form error message shown when the order key does not match. */
64 esc_html__( 'Order key mismatch.', 'woocommerce-pos' ),
65 /* translators: Checkout/payment form error message title. */
66 esc_html__( 'Error', 'woocommerce-pos' ),
67 array( 'response' => 403 )
68 );
69 }
70
71 // Check for 'wcpos_jwt' and fall back to 'token' if not present.
72 // remove 'token' when wcpos_jwt is fully implemented.
73 $token_key = isset( $_GET['wcpos_jwt'] ) ? 'wcpos_jwt' : ( isset( $_GET['token'] ) ? 'token' : null );
74
75 if ( null === $token_key || ! isset( $_GET[ $token_key ] ) ) {
76 wp_die(
77 /* translators: Checkout/payment form error message shown when no cashier token is provided. */
78 esc_html__( 'Token not provided.', 'woocommerce-pos' ),
79 /* translators: Checkout/payment form error message title. */
80 esc_html__( 'Error', 'woocommerce-pos' ),
81 array( 'response' => 403 )
82 );
83 }
84
85 // Verify the cashier is authorized to access the order.
86 $provided_token = sanitize_text_field( wp_unslash( $_GET[ $token_key ] ) );
87 $auth = AuthService::instance();
88 $user = $auth->validate_token( $provided_token );
89 if ( is_wp_error( $user ) ) {
90 wp_die(
91 /* translators: Checkout/payment form error message shown when the cashier token does not match. */
92 esc_html__( 'Cashier token mismatch.', 'woocommerce-pos' ),
93 /* translators: Checkout/payment form error message title. */
94 esc_html__( 'Error', 'woocommerce-pos' ),
95 array( 'response' => 403 )
96 );
97 }
98
99 // set customer.
100 wp_set_current_user( $order->get_customer_id() );
101
102 /*
103 * The pay nonce was minted in Templates\Payment with the logged-out nonce
104 * identity forced to 0 (its nonce_user_logged_out filter). That filter only
105 * exists while the template renders — it is not registered on this POST,
106 * which WooCommerce's own pay handler processes later on this same 'wp'
107 * hook (priority 20). Without the mirror here, a guest-session cookie
108 * (set by the pay page itself, and always replayed by the iOS/Android
109 * WebViews) makes WC_Session_Handler resolve the logged-out identity to
110 * its 't_…' customer id at verify time, the nonce hash no longer matches,
111 * and WC_Form_Handler::pay_action() drops the payment silently.
112 * Priority 20 so it wins over WC_Session_Handler's filter (priority 10).
113 */
114 add_filter( 'nonce_user_logged_out', array( $this, 'nonce_user_logged_out' ), 20, 2 );
115 }
116 }
117
118 /**
119 * Force the logged-out nonce identity to 0 for the pay nonce, matching the
120 * identity Templates\Payment mints it with.
121 *
122 * @param int|string $uid The logged-out nonce identity.
123 * @param string|int $action The nonce action.
124 *
125 * @return int|string
126 */
127 public function nonce_user_logged_out( $uid, $action ) {
128 if ( 'woocommerce-pay' === $action ) {
129 return 0;
130 }
131
132 return $uid;
133 }
134
135 /**
136 * Process the coupon action.
137 */
138 public function coupon_action() {
139 global $wp;
140
141 $is_coupon_request = isset( $_POST['pos_apply_coupon'] ) || isset( $_POST['pos_remove_coupon'] );
142 if ( ! woocommerce_pos_request() || ! $is_coupon_request ) {
143 return;
144 }
145
146 // Check for nonce.
147 if ( ! isset( $_POST['pos_coupon_nonce'] ) || ! wp_verify_nonce( $_POST['pos_coupon_nonce'], 'pos_coupon_action' ) ) {
148 return;
149 }
150
151 $order_id = absint( $wp->query_vars['order-pay'] );
152 $order = wc_get_order( $order_id );
153
154 if ( isset( $_POST['pos_apply_coupon'] ) ) {
155 $coupon_code = isset( $_POST['pos_coupon_code'] ) ? sanitize_text_field( wp_unslash( $_POST['pos_coupon_code'] ) ) : '';
156 $apply_result = $order->apply_coupon( $coupon_code );
157 if ( is_wp_error( $apply_result ) ) {
158 wc_add_notice( $apply_result->get_error_message(), 'error' );
159 }
160 } elseif ( isset( $_POST['pos_remove_coupon'] ) ) {
161 $coupon_code = sanitize_text_field( wp_unslash( $_POST['pos_remove_coupon'] ) );
162
163 $remove_result = $order->remove_coupon( $coupon_code );
164 if ( ! $remove_result ) {
165 wc_add_notice( __( 'Error', 'woocommerce' ) );
166 }
167 }
168 }
169 }
170