diff --git a/includes/wccom-site/class-wc-wccom-site.php b/includes/wccom-site/class-wc-wccom-site.php index 6aacf47cc95..7e8200c198f 100644 --- a/includes/wccom-site/class-wc-wccom-site.php +++ b/includes/wccom-site/class-wc-wccom-site.php @@ -15,6 +15,8 @@ defined( 'ABSPATH' ) || exit; */ class WC_WCCOM_Site { + const AUTH_ERROR_FILTER_NAME = 'wccom_auth_error'; + /** * Load the WCCOM site class. * @@ -53,23 +55,78 @@ class WC_WCCOM_Site { $auth_header = self::get_authorization_header(); if ( empty( $auth_header ) ) { + add_filter( + self::AUTH_ERROR_FILTER_NAME, + function() { + return new WP_Error( + WC_REST_WCCOM_Site_Installer_Errors::NO_AUTH_HEADER_CODE, + WC_REST_WCCOM_Site_Installer_Errors::NO_AUTH_HEADER_MESSAGE, + array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::NO_AUTH_HEADER_HTTP_CODE ) + ); + } + ); return false; } // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $request_auth = trim( $auth_header ); if ( stripos( $request_auth, 'Bearer ' ) !== 0 ) { + add_filter( + self::AUTH_ERROR_FILTER_NAME, + function() { + return new WP_Error( + WC_REST_WCCOM_Site_Installer_Errors::INVALID_AUTH_HEADER_CODE, + WC_REST_WCCOM_Site_Installer_Errors::INVALID_AUTH_HEADER_MESSAGE, + array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::INVALID_AUTH_HEADER_HTTP_CODE ) + ); + } + ); return false; } if ( empty( $_SERVER['HTTP_X_WOO_SIGNATURE'] ) ) { + add_filter( + self::AUTH_ERROR_FILTER_NAME, + function() { + return new WP_Error( + WC_REST_WCCOM_Site_Installer_Errors::NO_SIGNATURE_HEADER_CODE, + WC_REST_WCCOM_Site_Installer_Errors::NO_SIGNATURE_HEADER_MESSAGE, + array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::NO_SIGNATURE_HEADER_HTTP_CODE ) + ); + } + ); return false; } require_once WC_ABSPATH . 'includes/admin/helper/class-wc-helper-options.php'; $access_token = trim( substr( $request_auth, 7 ) ); $site_auth = WC_Helper_Options::get( 'auth' ); - if ( empty( $site_auth['access_token'] ) || ! hash_equals( $access_token, $site_auth['access_token'] ) ) { + + if ( empty( $site_auth['access_token'] ) ) { + add_filter( + self::AUTH_ERROR_FILTER_NAME, + function() { + return new WP_Error( + WC_REST_WCCOM_Site_Installer_Errors::SITE_NOT_CONNECTED_CODE, + WC_REST_WCCOM_Site_Installer_Errors::SITE_NOT_CONNECTED_MESSAGE, + array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::SITE_NOT_CONNECTED_HTTP_CODE ) + ); + } + ); + return false; + } + + if ( ! hash_equals( $access_token, $site_auth['access_token'] ) ) { + add_filter( + self::AUTH_ERROR_FILTER_NAME, + function() { + return new WP_Error( + WC_REST_WCCOM_Site_Installer_Errors::INVALID_TOKEN_CODE, + WC_REST_WCCOM_Site_Installer_Errors::INVALID_TOKEN_MESSAGE, + array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::INVALID_TOKEN_HTTP_CODE ) + ); + } + ); return false; } @@ -77,11 +134,31 @@ class WC_WCCOM_Site { $signature = trim( $_SERVER['HTTP_X_WOO_SIGNATURE'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( ! self::verify_wccom_request( $body, $signature, $site_auth['access_token_secret'] ) ) { + add_filter( + self::AUTH_ERROR_FILTER_NAME, + function() { + return new WP_Error( + WC_REST_WCCOM_Site_Installer_Errors::REQUEST_VERIFICATION_FAILED_CODE, + WC_REST_WCCOM_Site_Installer_Errors::REQUEST_VERIFICATION_FAILED_MESSAGE, + array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::REQUEST_VERIFICATION_FAILED_HTTP_CODE ) + ); + } + ); return false; } $user = get_user_by( 'id', $site_auth['user_id'] ); if ( ! $user ) { + add_filter( + self::AUTH_ERROR_FILTER_NAME, + function() { + return new WP_Error( + WC_REST_WCCOM_Site_Installer_Errors::USER_NOT_FOUND_CODE, + WC_REST_WCCOM_Site_Installer_Errors::USER_NOT_FOUND_MESSAGE, + array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::USER_NOT_FOUND_HTTP_CODE ) + ); + } + ); return false; } diff --git a/includes/wccom-site/rest-api/class-wc-rest-wccom-site-installer-errors.php b/includes/wccom-site/rest-api/class-wc-rest-wccom-site-installer-errors.php index d7d9b0034da..3f56e688ead 100644 --- a/includes/wccom-site/rest-api/class-wc-rest-wccom-site-installer-errors.php +++ b/includes/wccom-site/rest-api/class-wc-rest-wccom-site-installer-errors.php @@ -15,10 +15,66 @@ defined( 'ABSPATH' ) || exit; */ class WC_REST_WCCOM_Site_Installer_Errors { + /** + * Not unauthenticated generic error + */ + const NOT_AUTHENTICATED_CODE = 'not_authenticated'; + const NOT_AUTHENTICATED_MESSAGE = 'Authentication required'; + const NOT_AUTHENTICATED_HTTP_CODE = 401; + + /** + * No Authorization header + */ + const NO_AUTH_HEADER_CODE = 'no_auth_header'; + const NO_AUTH_HEADER_MESSAGE = 'No header "Authorization" present'; + const NO_AUTH_HEADER_HTTP_CODE = 400; + + /** + * Authorization header invalid + */ + const INVALID_AUTH_HEADER_CODE = 'no_auth_header'; + const INVALID_AUTH_HEADER_MESSAGE = 'Header "Authorization" is invalid'; + const INVALID_AUTH_HEADER_HTTP_CODE = 400; + + /** + * No Signature header + */ + const NO_SIGNATURE_HEADER_CODE = 'no_signature_header'; + const NO_SIGNATURE_HEADER_MESSAGE = 'No header "X-Woo-Signature" present'; + const NO_SIGNATURE_HEADER_HTTP_CODE = 400; + + /** + * Site not connected to WooCommerce.com + */ + const SITE_NOT_CONNECTED_CODE = 'site_not_connnected'; + const SITE_NOT_CONNECTED_MESSAGE = 'Site not connected to WooCommerce.com'; + const SITE_NOT_CONNECTED_HTTP_CODE = 401; + + /** + * Provided access token is not valid + */ + const INVALID_TOKEN_CODE = 'invalid_token'; + const INVALID_TOKEN_MESSAGE = 'Invalid access token provided'; + const INVALID_TOKEN_HTTP_CODE = 401; + + /** + * Request verification by provided signature failed + */ + const REQUEST_VERIFICATION_FAILED_CODE = 'request_verification_failed'; + const REQUEST_VERIFICATION_FAILED_MESSAGE = 'Request verification by signature failed'; + const REQUEST_VERIFICATION_FAILED_HTTP_CODE = 400; + + /** + * User doesn't exist + */ + const USER_NOT_FOUND_CODE = 'user_not_found'; + const USER_NOT_FOUND_MESSAGE = 'Token owning user not found'; + const USER_NOT_FOUND_HTTP_CODE = 401; + /** * No permissions error */ - const NO_PERMISSION_CODE = 'woocommerce_rest_cannot_install_product'; + const NO_PERMISSION_CODE = 'forbidden'; const NO_PERMISSION_MESSAGE = 'You do not have permission to install plugin or theme'; - const NO_PERMISSION_HTTP_CODE = 401; + const NO_PERMISSION_HTTP_CODE = 403; } diff --git a/includes/wccom-site/rest-api/endpoints/class-wc-rest-wccom-site-installer-controller.php b/includes/wccom-site/rest-api/endpoints/class-wc-rest-wccom-site-installer-controller.php index 86fe9ac2332..c2169e4fe8c 100644 --- a/includes/wccom-site/rest-api/endpoints/class-wc-rest-wccom-site-installer-controller.php +++ b/includes/wccom-site/rest-api/endpoints/class-wc-rest-wccom-site-installer-controller.php @@ -69,11 +69,24 @@ class WC_REST_WCCOM_Site_Installer_Controller extends WC_REST_Controller { * @return bool|WP_Error */ public function check_permission( $request ) { - if ( ! current_user_can( 'install_plugins' ) || ! current_user_can( 'install_themes' ) ) { + $current_user = wp_get_current_user(); + + if ( empty( $current_user ) || ( $current_user instanceof WP_User && ! $current_user->exists() ) ) { + return apply_filters( + WC_WCCOM_Site::AUTH_ERROR_FILTER_NAME, + new WP_Error( + WC_REST_WCCOM_Site_Installer_Errors::NOT_AUTHENTICATED_CODE, + WC_REST_WCCOM_Site_Installer_Errors::NOT_AUTHENTICATED_MESSAGE, + array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::NOT_AUTHENTICATED_HTTP_CODE ) + ) + ); + } + + if ( ! user_can( $current_user, 'install_plugins' ) || ! user_can( $current_user, 'install_themes' ) ) { return new WP_Error( - \WC_REST_WCCOM_Site_Installer_Errors::NO_PERMISSION_CODE, - \WC_REST_WCCOM_Site_Installer_Errors::NO_PERMISSION_MESSAGE, - array( 'status' => \WC_REST_WCCOM_Site_Installer_Errors::NO_PERMISSION_HTTP_CODE ) + WC_REST_WCCOM_Site_Installer_Errors::NO_PERMISSION_CODE, + WC_REST_WCCOM_Site_Installer_Errors::NO_PERMISSION_MESSAGE, + array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::NO_PERMISSION_HTTP_CODE ) ); }