PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.18
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.18
1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 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 All 163 releases
← All changes | includes/API.php +73 -21 1.10.31.10.18 View file →
@@ -84,8 +84,9 @@
84 84
85 85 // These filters allow changes to the WC REST API response.
86 86 add_filter( 'rest_dispatch_request', array( $this, 'rest_dispatch_request' ), 10, 4 );
87 87 add_filter( 'rest_pre_dispatch', array( $this, 'rest_pre_dispatch' ), 10, 3 );
88 + add_filter( 'rest_pre_dispatch', array( $this, 'clear_third_party_jwt_error' ), 50, 3 );
88 89 add_filter( 'rest_post_dispatch', array( $this, 'rest_post_dispatch' ), 10, 3 );
89 90 }
90 91
91 92 /**
@@ -329,13 +330,14 @@
329 330 * 1. WooCommerce issue #26847: determine_current_user may not be called when
330 331 * WordPress has already cached the current user. We attempt auth here as a
331 332 * fallback.
332 333 *
333 - * 2. JWT plugin conflict: a third-party JWT plugin (e.g. jwt-authentication-for-wp-rest-api)
334 - * sees our Bearer token, fails to validate it with its own secret, and returns
335 - * a WP_Error via rest_authentication_errors at priority 10. We run at priority 50
336 - * and attempt our own Bearer-token validation. If it succeeds, we clear the
337 - * stale error — our authentication wins.
334 + * 2. JWT plugin conflict: a third-party JWT plugin sees our Bearer token, fails
335 + * to validate it with its own secret, and returns a WP_Error via
336 + * rest_authentication_errors at priority 10. We run at priority 50 and attempt
337 + * our own Bearer-token validation. If it succeeds, we clear the stale error —
338 + * our authentication wins. (jwt-authentication-for-wp-rest-api surfaces its
339 + * error through rest_pre_dispatch instead; see clear_third_party_jwt_error().)
338 340 *
339 341 * @param mixed $errors Authentication errors.
340 342 *
341 343 * @return mixed
@@ -348,19 +350,9 @@
348 350 if ( ! empty( $errors ) ) {
349 351 // Only clear errors that originate from JWT authentication plugins. Errors
350 352 // from other mechanisms (maintenance locks, IP restrictions, etc.) should
351 353 // be passed through even when the WCPOS Bearer token is valid.
352 - $is_jwt_plugin_error = is_wp_error( $errors ) && 0 === strpos( $errors->get_error_code(), 'jwt_auth_' );
353 -
354 - if ( $is_jwt_plugin_error && ! $this->authenticated_via_wcpos ) {
355 - $user_id = $this->authenticate( false );
356 - if ( $user_id && ! is_wp_error( $user_id ) ) {
357 - wp_set_current_user( $user_id );
358 - $this->authenticated_via_wcpos = true;
359 - }
360 - }
361 -
362 - if ( $this->authenticated_via_wcpos && $is_jwt_plugin_error ) {
354 + if ( $this->is_third_party_jwt_error( $errors ) && $this->ensure_authenticated_via_wcpos() ) {
363 355 return null;
364 356 }
365 357
366 358 return $errors;
@@ -366,20 +358,80 @@
366 358 return $errors;
367 359 }
368 360
369 361 // check if determine_current_user has been called.
370 - if ( ! $this->is_auth_checked ) {
371 - // Authentication hasn't occurred during `determine_current_user`, so check auth.
362 + if ( ! $this->is_auth_checked && $this->ensure_authenticated_via_wcpos() ) {
363 + // Authentication hadn't occurred during `determine_current_user`, but our token is valid.
364 + return true;
365 + }
366 +
367 + return $errors;
368 + }
369 +
370 + /**
371 + * Clear a third-party JWT plugin's stale error from the dispatch result.
372 + *
373 + * The plugin jwt-authentication-for-wp-rest-api (verified at 1.5.0) validates every
374 + * Bearer token in determine_current_user (priority 10) with its own secret. Ours fails,
375 + * so it stores a `jwt_auth_invalid_token` WP_Error and returns the user untouched;
376 + * our priority-20 filter then authenticates the request. The plugin later returns
377 + * that stored error from rest_pre_dispatch (priority 10, registered at
378 + * plugins_loaded), which replaces the dispatch result with a 403.
379 + *
380 + * Priority 50: after the plugin's callback, and after our own priority-10
381 + * permission gate, whose `woocommerce_pos_rest_*` errors must pass through untouched.
382 + *
383 + * Unlike rest_authentication_errors(), this never switches the current user: the
384 + * priority-10 gate and the core-order audit guard have already judged the user in
385 + * scope, so the error is cleared only when our token resolves to that same user.
386 + *
387 + * @param mixed $result Dispatch result, or null to not hijack the request.
388 + * @param WP_REST_Server $server Server instance.
389 + * @param WP_REST_Request $request Request used to generate the response.
390 + *
391 + * @return mixed
392 + */
393 + public function clear_third_party_jwt_error( $result, $server, $request ) {
394 + if ( ! $this->is_third_party_jwt_error( $result ) ) {
395 + return $result;
396 + }
397 +
398 + if ( ! $this->authenticated_via_wcpos ) {
372 399 $user_id = $this->authenticate( false );
400 + if ( $user_id && ! is_wp_error( $user_id ) && get_current_user_id() === (int) $user_id ) {
401 + $this->authenticated_via_wcpos = true;
402 + }
403 + }
404 +
405 + return $this->authenticated_via_wcpos ? null : $result;
406 + }
407 +
408 + /**
409 + * Whether a value is a WP_Error raised by a third-party JWT plugin (`jwt_auth_*`).
410 + *
411 + * @param mixed $maybe_error Value to inspect.
412 + *
413 + * @return bool
414 + */
415 + private function is_third_party_jwt_error( $maybe_error ): bool {
416 + return is_wp_error( $maybe_error ) && 0 === strpos( $maybe_error->get_error_code(), 'jwt_auth_' );
417 + }
418 +
419 + /**
420 + * Authenticate the request with its WCPOS Bearer token if that hasn't happened yet.
421 + *
422 + * @return bool True when the request is authenticated via a WCPOS-issued token.
423 + */
424 + private function ensure_authenticated_via_wcpos(): bool {
425 + if ( ! $this->authenticated_via_wcpos ) {
426 + $user_id = $this->authenticate( false );
373 427 if ( $user_id && ! is_wp_error( $user_id ) ) {
374 428 wp_set_current_user( $user_id );
375 429 $this->authenticated_via_wcpos = true;
376 -
377 - return true;
378 430 }
379 431 }
380 432
381 - return $errors;
433 + return $this->authenticated_via_wcpos;
382 434 }
383 435
384 436 /**
385 437 * Extract the Authorization Bearer token from the request.