diff --git a/changelog.txt b/changelog.txt index 95b8ea6db..83b427e71 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,7 @@ == Changelog == += 3.4.1 = +FIX - improve security while processing AJAX requests in Admin Panel + = 3.4.0 = * ENHANCEMENT - removed `udx/lib-settings` package dependency for security reasons. * ENHANCEMENT - removed `udx/lib-utility` package dependency for security reasons. diff --git a/changes.md b/changes.md index cc6decffb..e8821c80d 100644 --- a/changes.md +++ b/changes.md @@ -1,3 +1,6 @@ +#### 3.4.1 +FIX - improve security while processing AJAX requests in Admin Panel + #### 3.4.0 * ENHANCEMENT - removed `udx/lib-settings` package dependency for security reasons. * ENHANCEMENT - removed `udx/lib-utility` package dependency for security reasons. diff --git a/composer.lock b/composer.lock index a38318e53..b3e77e3b7 100644 --- a/composer.lock +++ b/composer.lock @@ -269,15 +269,15 @@ }, { "name": "udx/lib-ud-api-client", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "git@github.com:udx/lib-ud-api-client", - "reference": "1.2.2" + "reference": "1.2.3" }, "dist": { "type": "zip", - "url": "https://github.com/udx/lib-ud-api-client/archive/1.2.2.zip" + "url": "https://github.com/udx/lib-ud-api-client/archive/1.2.3.zip" }, "require": { "php": ">=5.3" @@ -312,15 +312,15 @@ }, { "name": "udx/lib-wp-bootstrap", - "version": "1.3.1", + "version": "1.3.2", "source": { "type": "git", "url": "git@github.com:udx/lib-wp-bootstrap", - "reference": "1.3.1" + "reference": "1.3.2" }, "dist": { "type": "zip", - "url": "https://github.com/udx/lib-wp-bootstrap/archive/1.3.1.zip" + "url": "https://github.com/udx/lib-wp-bootstrap/archive/1.3.2.zip" }, "require": { "php": ">=5.3" @@ -1603,5 +1603,5 @@ "php": ">=5.6.20" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/lib/classes/class-ajax.php b/lib/classes/class-ajax.php index 56bee4513..cf83e44e7 100644 --- a/lib/classes/class-ajax.php +++ b/lib/classes/class-ajax.php @@ -48,6 +48,8 @@ public function __construct() { * @author peshkov@UD */ public function request() { + check_ajax_referer('sm_inline_sync'); + global $doing_manual_sync; $response = array( diff --git a/lib/classes/class-bootstrap.php b/lib/classes/class-bootstrap.php index 1cbe611a4..dab3d83a2 100644 --- a/lib/classes/class-bootstrap.php +++ b/lib/classes/class-bootstrap.php @@ -1216,6 +1216,9 @@ public function admin_init() { /* Attachment or upload page */ wp_register_script('wp-stateless-uploads-js', $this->path('static/scripts/wp-stateless-uploads.js', 'url'), array('jquery'), self::$version); + wp_localize_script('wp-stateless-uploads-js', 'stateless_upload', [ + 'inline_sync_nonce' => wp_create_nonce('sm_inline_sync'), + ]); /* Setup wizard styles. */ wp_register_style('wp-stateless-setup-wizard', $this->path('static/styles/wp-stateless-setup-wizard.css', 'url'), array(), self::$version); diff --git a/lib/classes/class-errors.php b/lib/classes/class-errors.php index d5099c9d9..b2b27026f 100644 --- a/lib/classes/class-errors.php +++ b/lib/classes/class-errors.php @@ -181,7 +181,10 @@ public function admin_notices() { wp_localize_script( "ud-dismiss", "_ud_vars", array( "ajaxurl" => admin_url( 'admin-ajax.php' ), ) ); - + wp_localize_script( "sateless-error-notice-js", "stateless_error_notice_vars", array( + "dismiss_nonce" => wp_create_nonce( 'stateless_notice_dismiss' ), + "enable_action_nonce" => wp_create_nonce( 'stateless_enable_notice_button_action' ), + ) ); //** Don't show the message if the user has no enough permissions. */ if ( ! function_exists( 'wp_get_current_user' ) ) { @@ -248,20 +251,24 @@ public function admin_notices() { * dismiss the notice ajax callback * @throws \Exception */ - public function dismiss_notices(){ + public function dismiss_notices() { + check_ajax_referer('stateless_notice_dismiss'); + $response = array( 'success' => '0', 'error' => __( 'There was an error in request.', $this->domain ), ); + $error = false; - if( empty($_POST['key']) && strpos($_POST['key'], 'dismissed_notice_') !== false ) { + $option_key = isset($_POST['key']) ? sanitize_key($_POST['key']) : ''; + + if ( strpos($option_key, 'dismissed_') !== 0 ) { $response['error'] = __( 'Invalid key', $this->domain ); $error = true; } - else { - $option_key = sanitize_key($_POST['key']); - update_option( $option_key, time() ); + + if ( !$error && update_option( $option_key, time() ) ) { $response['success'] = '1'; $response['error'] = null; } @@ -274,6 +281,8 @@ public function dismiss_notices(){ * @throws \Exception */ public function stateless_enable_notice_button_action(){ + check_ajax_referer('stateless_enable_notice_button_action'); + $response = array( 'success' => '1', ); diff --git a/readme.txt b/readme.txt index 25f30227e..ff8238722 100644 --- a/readme.txt +++ b/readme.txt @@ -5,8 +5,8 @@ Tags: google, google cloud, google cloud storage, cdn, uploads, media, stateless License: GPLv2 or later Requires PHP: 8.0 Requires at least: 5.0 -Tested up to: 6.4.2 -Stable tag: 3.4.0 +Tested up to: 6.4.3 +Stable tag: 3.4.1 Upload and serve your WordPress media files from Google Cloud Storage. @@ -112,6 +112,9 @@ Before upgrading to WP-Stateless 3.2.0, please, make sure you use PHP 7.2 or abo Before upgrading to WP-Stateless 3.0, please, make sure you tested it on your development environment. == Changelog == += 3.4.1 = +FIX - improve security while processing AJAX requests in Admin Panel + = 3.4.0 = * ENHANCEMENT - removed `udx/lib-settings` package dependency for security reasons. * ENHANCEMENT - removed `udx/lib-utility` package dependency for security reasons. diff --git a/static/scripts/error-notice.js b/static/scripts/error-notice.js index 19931d0bc..1eb5b7254 100644 --- a/static/scripts/error-notice.js +++ b/static/scripts/error-notice.js @@ -15,6 +15,7 @@ jQuery( document ).ready( function ($) { var data = { action: 'stateless_enable_notice_button_action', key: _this.data('key'), + _ajax_nonce: stateless_error_notice_vars.enable_action_nonce ?? '', } jQuery.post( ajaxurl, data, function ( result_data ) { @@ -41,6 +42,7 @@ jQuery( document ).ready( function ($) { var data = { action: 'stateless_notice_dismiss', key: _this.data('key'), + _ajax_nonce: stateless_error_notice_vars.dismiss_nonce ?? '', } jQuery.post( ajaxurl, data, function ( result_data ) { diff --git a/static/scripts/wp-stateless-uploads.js b/static/scripts/wp-stateless-uploads.js index 266260b8d..bfdcfc769 100644 --- a/static/scripts/wp-stateless-uploads.js +++ b/static/scripts/wp-stateless-uploads.js @@ -19,7 +19,8 @@ jQuery(document).ready(function(){ data: { action: that.data('type') == 'image' ? "stateless_process_image" : "stateless_process_file", id: that.data('id'), - size: that.data('size') + size: that.data('size'), + _ajax_nonce: stateless_upload.inline_sync_nonce ?? '', } }) .done(function( response ) { diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index a5e38b9de..c2fc7d4c3 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -264,16 +264,16 @@ }, { "name": "udx/lib-ud-api-client", - "version": "1.2.2", - "version_normalized": "1.2.2.0", + "version": "1.2.3", + "version_normalized": "1.2.3.0", "source": { "type": "git", "url": "git@github.com:udx/lib-ud-api-client", - "reference": "1.2.2" + "reference": "1.2.3" }, "dist": { "type": "zip", - "url": "https://github.com/udx/lib-ud-api-client/archive/1.2.2.zip" + "url": "https://github.com/udx/lib-ud-api-client/archive/1.2.3.zip" }, "require": { "php": ">=5.3" @@ -310,16 +310,16 @@ }, { "name": "udx/lib-wp-bootstrap", - "version": "1.3.1", - "version_normalized": "1.3.1.0", + "version": "1.3.2", + "version_normalized": "1.3.2.0", "source": { "type": "git", "url": "git@github.com:udx/lib-wp-bootstrap", - "reference": "1.3.1" + "reference": "1.3.2" }, "dist": { "type": "zip", - "url": "https://github.com/udx/lib-wp-bootstrap/archive/1.3.1.zip" + "url": "https://github.com/udx/lib-wp-bootstrap/archive/1.3.2.zip" }, "require": { "php": ">=5.3" diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index c6fbe42cb..04a94e91c 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'wpcloud/wp-stateless', 'pretty_version' => 'dev-latest', 'version' => 'dev-latest', - 'reference' => '4e811ffcf935c543ab66a31c9562301a405d988d', + 'reference' => '4485e93b09271c7d1d632d20406de711e4d8b391', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -50,18 +50,18 @@ ), ), 'udx/lib-ud-api-client' => array( - 'pretty_version' => '1.2.2', - 'version' => '1.2.2.0', - 'reference' => '1.2.2', + 'pretty_version' => '1.2.3', + 'version' => '1.2.3.0', + 'reference' => '1.2.3', 'type' => 'library', 'install_path' => __DIR__ . '/../udx/lib-ud-api-client', 'aliases' => array(), 'dev_requirement' => false, ), 'udx/lib-wp-bootstrap' => array( - 'pretty_version' => '1.3.1', - 'version' => '1.3.1.0', - 'reference' => '1.3.1', + 'pretty_version' => '1.3.2', + 'version' => '1.3.2.0', + 'reference' => '1.3.2', 'type' => 'library', 'install_path' => __DIR__ . '/../udx/lib-wp-bootstrap', 'aliases' => array(), @@ -70,7 +70,7 @@ 'wpcloud/wp-stateless' => array( 'pretty_version' => 'dev-latest', 'version' => 'dev-latest', - 'reference' => '4e811ffcf935c543ab66a31c9562301a405d988d', + 'reference' => '4485e93b09271c7d1d632d20406de711e4d8b391', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), diff --git a/vendor/udx/lib-ud-api-client/changes.md b/vendor/udx/lib-ud-api-client/changes.md index 4a53a070a..24e6a33db 100644 --- a/vendor/udx/lib-ud-api-client/changes.md +++ b/vendor/udx/lib-ud-api-client/changes.md @@ -1,3 +1,7 @@ +### 1.2.3 + +* Improve security while processing AJAX requests in Admin Panel. + ### 1.2.2 * Remove dependency from `udx/lib-utility`. diff --git a/vendor/udx/lib-ud-api-client/gruntfile.js b/vendor/udx/lib-ud-api-client/gruntfile.js index 3a68976fb..904ab6b69 100644 --- a/vendor/udx/lib-ud-api-client/gruntfile.js +++ b/vendor/udx/lib-ud-api-client/gruntfile.js @@ -2,7 +2,7 @@ * Build Plugin. * * @author potanin@UD - * @version 1.2.2 + * @version 1.2.3 * @param grunt */ module.exports = function( grunt ) { diff --git a/vendor/udx/lib-ud-api-client/lib/classes/class-bootstrap.php b/vendor/udx/lib-ud-api-client/lib/classes/class-bootstrap.php index 7d2845ebe..21af6e459 100644 --- a/vendor/udx/lib-ud-api-client/lib/classes/class-bootstrap.php +++ b/vendor/udx/lib-ud-api-client/lib/classes/class-bootstrap.php @@ -18,7 +18,7 @@ class Bootstrap extends Scaffold { /** * */ - public static $version = '1.2.2'; + public static $version = '1.2.3'; /** * diff --git a/vendor/udx/lib-ud-api-client/lib/classes/class-update-checker.php b/vendor/udx/lib-ud-api-client/lib/classes/class-update-checker.php index d095356db..d39c4d57a 100644 --- a/vendor/udx/lib-ud-api-client/lib/classes/class-update-checker.php +++ b/vendor/udx/lib-ud-api-client/lib/classes/class-update-checker.php @@ -349,19 +349,20 @@ public function check_response_for_errors( $response ) { $plugins = get_plugins(); $name = isset( $plugins[$this->name] ) ? $plugins[$this->name]['Name'] : $this->name; + $nonce = wp_create_nonce( 'ud_api_dismiss' ); if ( isset( $response->errors['no_key'] ) && $response->errors['no_key'] == 'no_key' && isset( $response->errors['no_subscription'] ) && $response->errors['no_subscription'] == 'no_subscription' ) { $no_key_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_no_key', '' ); $show_no_key_error = $this->check_dismiss_time( $no_key_dismissed ); if( $show_no_key_error ) { - $this->errors[] = sprintf( __( 'A license key for %s could not be found. Maybe you forgot to enter a license key when setting up %s, or the key was deactivated in your account. You can reactivate or purchase a license key from your account Licences | dismiss.', $this->text_domain ), $name, $name, $this->renew_license_url, sanitize_key( $name ) ); + $this->errors[] = sprintf( __( 'A license key for %s could not be found. Maybe you forgot to enter a license key when setting up %s, or the key was deactivated in your account. You can reactivate or purchase a license key from your account Licences | dismiss.', $this->text_domain ), $name, $name, $this->renew_license_url, sanitize_key( $name ), $nonce ); } $no_subscription_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_no_subscription', '' ); $show_no_subscription_error = $this->check_dismiss_time( $no_subscription_dismissed ); if( $show_no_subscription_error ) { - $this->errors[] = sprintf( __( 'A subscription for %s could not be found. You can purchase a subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ) ); + $this->errors[] = sprintf( __( 'A subscription for %s could not be found. You can purchase a subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ), $nonce ); } } else if ( isset( $response->errors['exp_license'] ) && $response->errors['exp_license'] == 'exp_license' ) { @@ -369,7 +370,7 @@ public function check_response_for_errors( $response ) { $exp_license_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_exp_license', '' ); $show_exp_license_error = $this->check_dismiss_time( $exp_license_dismissed ); if( $show_exp_license_error ) { - $this->errors[] = sprintf( __( 'The license key for %s has expired. You can reactivate or get a license key from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ) ); + $this->errors[] = sprintf( __( 'The license key for %s has expired. You can reactivate or get a license key from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ), $nonce ); } } else if ( isset( $response->errors['hold_subscription'] ) && $response->errors['hold_subscription'] == 'hold_subscription' ) { @@ -377,7 +378,7 @@ public function check_response_for_errors( $response ) { $hold_subscription_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_hold_subscription', '' ); $show_hold_subscription_error = $this->check_dismiss_time( $hold_subscription_dismissed ); if( $show_hold_subscription_error ) { - $this->errors[] = sprintf( __( 'The subscription for %s is on-hold. You can reactivate the subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ) ); + $this->errors[] = sprintf( __( 'The subscription for %s is on-hold. You can reactivate the subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ), $nonce ); } } else if ( isset( $response->errors['cancelled_subscription'] ) && $response->errors['cancelled_subscription'] == 'cancelled_subscription' ) { @@ -385,7 +386,7 @@ public function check_response_for_errors( $response ) { $cancelled_subscription_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_cancelled_subscription', '' ); $show_cancelled_subscription_error = $this->check_dismiss_time( $cancelled_subscription_dismissed ); if( $show_cancelled_subscription_error ) { - $this->errors[] = sprintf( __( 'The subscription for %s has been cancelled. You can renew the subscription from your account dashboard. A new license key will be emailed to you after your order has been completed. dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ) ); + $this->errors[] = sprintf( __( 'The subscription for %s has been cancelled. You can renew the subscription from your account dashboard. A new license key will be emailed to you after your order has been completed. dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ), $nonce ); } } else if ( isset( $response->errors['exp_subscription'] ) && $response->errors['exp_subscription'] == 'exp_subscription' ) { @@ -393,7 +394,7 @@ public function check_response_for_errors( $response ) { $exp_subscription_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_exp_subscription', '' ); $show_exp_subscription_error = $this->check_dismiss_time( $exp_subscription_dismissed ); if( $show_exp_subscription_error ) { - $this->errors[] = sprintf( __( 'The subscription for %s has expired. You can reactivate the subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ) ) ; + $this->errors[] = sprintf( __( 'The subscription for %s has expired. You can reactivate the subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ), $nonce ) ; } } else if ( isset( $response->errors['suspended_subscription'] ) && $response->errors['suspended_subscription'] == 'suspended_subscription' ) { @@ -401,7 +402,7 @@ public function check_response_for_errors( $response ) { $suspended_subscription_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_suspended_subscription', '' ); $show_suspended_subscription_error = $this->check_dismiss_time( $suspended_subscription_dismissed ); if( $show_suspended_subscription_error ) { - $this->errors[] = sprintf( __( 'The subscription for %s has been suspended. You can reactivate the subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ) ) ; + $this->errors[] = sprintf( __( 'The subscription for %s has been suspended. You can reactivate the subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ), $nonce ) ; } } else if ( isset( $response->errors['pending_subscription'] ) && $response->errors['pending_subscription'] == 'pending_subscription' ) { @@ -409,7 +410,7 @@ public function check_response_for_errors( $response ) { $pending_subscription_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_pending_subscription', '' ); $show_pending_subscription_error = $this->check_dismiss_time( $pending_subscription_dismissed ); if( $show_pending_subscription_error ) { - $this->errors[] = sprintf( __( 'The subscription for %s is still pending. You can check on the status of the subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ) ) ; + $this->errors[] = sprintf( __( 'The subscription for %s is still pending. You can check on the status of the subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ), $nonce ) ; } } else if ( isset( $response->errors['trash_subscription'] ) && $response->errors['trash_subscription'] == 'trash_subscription' ) { @@ -417,7 +418,7 @@ public function check_response_for_errors( $response ) { $trash_subscription_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_trash_subscription', '' ); $show_trash_subscription_error = $this->check_dismiss_time( $trash_subscription_dismissed ); if( $show_trash_subscription_error ) { - $this->errors[] = sprintf( __( 'The subscription for %s has been placed in the trash and will be deleted soon. You can get a new subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ) ) ; + $this->errors[] = sprintf( __( 'The subscription for %s has been placed in the trash and will be deleted soon. You can get a new subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ), $nonce ) ; } } else if ( isset( $response->errors['no_subscription'] ) && $response->errors['no_subscription'] == 'no_subscription' ) { @@ -425,7 +426,7 @@ public function check_response_for_errors( $response ) { $no_subscription_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_no_subscription', '' ); $show_no_subscription_error = $this->check_dismiss_time( $no_subscription_dismissed ); if( $show_no_subscription_error ) { - $this->errors[] = sprintf( __( 'A subscription for %s could not be found. You can get a subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ) ); + $this->errors[] = sprintf( __( 'A subscription for %s could not be found. You can get a subscription from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ), $nonce ); } } else if ( isset( $response->errors['no_activation'] ) && $response->errors['no_activation'] == 'no_activation' ) { @@ -433,7 +434,7 @@ public function check_response_for_errors( $response ) { $no_activation_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_no_activation', '' ); $show_no_activation_error = $this->check_dismiss_time( $no_activation_dismissed ); if( $show_no_activation_error ) { - $this->errors[] = sprintf( __( '%s has not been activated. Go to the settings page and enter the license key and license email to activate %s. dismiss.', $this->text_domain ), $name, $name, sanitize_key( $name ) ) ; + $this->errors[] = sprintf( __( '%s has not been activated. Go to the settings page and enter the license key and license email to activate %s. dismiss.', $this->text_domain ), $name, $name, sanitize_key( $name ), $nonce ) ; } } else if ( isset( $response->errors['no_key'] ) && $response->errors['no_key'] == 'no_key' ) { @@ -441,7 +442,7 @@ public function check_response_for_errors( $response ) { $no_key_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_no_key', '' ); $show_no_key_error = $this->check_dismiss_time( $no_key_dismissed ); if( $show_no_key_error ) { - $this->errors[] = sprintf( __( 'A license key for %s could not be found. Maybe you forgot to enter a license key when setting up %s, or the key was deactivated in your account. You can reactivate or get a license key from your account Licences | dismiss.', $this->text_domain ), $name, $name, $this->renew_license_url, sanitize_key( $name ) ); + $this->errors[] = sprintf( __( 'A license key for %s could not be found. Maybe you forgot to enter a license key when setting up %s, or the key was deactivated in your account. You can reactivate or get a license key from your account Licences | dismiss.', $this->text_domain ), $name, $name, $this->renew_license_url, sanitize_key( $name ), $nonce ); } } else if ( isset( $response->errors['download_revoked'] ) && $response->errors['download_revoked'] == 'download_revoked' ) { @@ -449,7 +450,7 @@ public function check_response_for_errors( $response ) { $download_revoked_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_download_revoked', '' ); $show_download_revoked_error = $this->check_dismiss_time( $download_revoked_dismissed ); if( $show_download_revoked_error ) { - $this->errors[] = sprintf( __( 'Download permission for %s has been revoked possibly due to a license key or subscription expiring. You can reactivate or get a license key from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ) ) ; + $this->errors[] = sprintf( __( 'Download permission for %s has been revoked possibly due to a license key or subscription expiring. You can reactivate or get a license key from your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ), $nonce ) ; } } else if ( isset( $response->errors['switched_subscription'] ) && $response->errors['switched_subscription'] == 'switched_subscription' ) { @@ -457,7 +458,7 @@ public function check_response_for_errors( $response ) { $switched_subscription_dismissed = get_option( 'dismissed_error_' . sanitize_key( $name ) . '_switched_subscription', '' ); $show_switched_subscription_error = $this->check_dismiss_time( $switched_subscription_dismissed ); if( $show_switched_subscription_error ) { - $this->errors[] = sprintf( __( 'You changed the subscription for %s, so you will need to enter your new API License Key in the settings page. The License Key should have arrived in your email inbox, if not you can get it by logging into your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ) ) ; + $this->errors[] = sprintf( __( 'You changed the subscription for %s, so you will need to enter your new API License Key in the settings page. The License Key should have arrived in your email inbox, if not you can get it by logging into your account dashboard | dismiss.', $this->text_domain ), $name, $this->renew_license_url, sanitize_key( $name ), $nonce ) ; } } @@ -499,6 +500,7 @@ public function print_scripts() { var data = { action: 'ud_api_dismiss', key: _this.data('key'), + _ajax_nonce: _this.data('nonce'), } jQuery.post( "", data, function ( result_data ) { @@ -541,21 +543,27 @@ public function check_dismiss_time( $time = '' ) { * @throws \Exception */ public function dismiss_notices(){ + check_ajax_referer('ud_api_dismiss'); + $response = array( 'success' => '0', 'error' => __( 'There was an error in request.', $this->text_domain ), ); + $error = false; - if( empty($_POST['key']) ) { - $response['error'] = __( 'Invalid key', $this->text_domain ); + $option_key = isset($_POST['key']) ? sanitize_key($_POST['key']) : ''; + + if ( strpos($option_key, 'dismissed_') !== 0 ) { + $response['error'] = __( 'Invalid key', $this->domain ); $error = true; } - - if ( ! $error && update_option( ( $_POST['key'] ), time() ) ) { + + if ( !$error && update_option( $option_key, time() ) ) { $response['success'] = '1'; + $response['error'] = null; } - + wp_send_json( $response ); } diff --git a/vendor/udx/lib-ud-api-client/package.json b/vendor/udx/lib-ud-api-client/package.json index 23c77afb9..d7eb558e6 100644 --- a/vendor/udx/lib-ud-api-client/package.json +++ b/vendor/udx/lib-ud-api-client/package.json @@ -1,6 +1,6 @@ { "name": "lib-ud-api-client", - "version": "1.2.2", + "version": "1.2.3", "description": "UD Client for WooCommerce API Manager", "repository": { "type": "git", diff --git a/vendor/udx/lib-wp-bootstrap/changes.md b/vendor/udx/lib-wp-bootstrap/changes.md index 5b8d6d10b..d4d30e312 100644 --- a/vendor/udx/lib-wp-bootstrap/changes.md +++ b/vendor/udx/lib-wp-bootstrap/changes.md @@ -1,3 +1,7 @@ +### 1.3.2 + +* Improve security while processing AJAX requests in Admin Panel. + ### 1.3.1 * Remove dependency from `udx/lib-utility`. diff --git a/vendor/udx/lib-wp-bootstrap/lib/classes/class-errors.php b/vendor/udx/lib-wp-bootstrap/lib/classes/class-errors.php index 845620dab..2d78ff9a0 100644 --- a/vendor/udx/lib-wp-bootstrap/lib/classes/class-errors.php +++ b/vendor/udx/lib-wp-bootstrap/lib/classes/class-errors.php @@ -156,6 +156,8 @@ public function admin_notices() { $errors = apply_filters( 'ud:errors:admin_notices', $this->errors, $this->args ); $messages = apply_filters( 'ud:messages:admin_notices', $this->messages, $this->args ); $warnings = apply_filters( 'ud:warnings:admin_notices', $this->warnings, $this->args ); + + $nonce = wp_create_nonce('ud_dismiss'); if( !empty( $errors ) || !empty( $messages ) || !empty( $warnings ) ) { echo ""; @@ -179,7 +181,11 @@ public function admin_notices() { $message = ''; $message = sprintf( __( '

%s has the following warnings:

%s', $this->domain ), $this->name, $message ); if( $this->dismiss ) { - $this->action_links[ 'warnings' ][] = '' . __( 'Dismiss this warning', $this->domain ) . ''; + $this->action_links[ 'warnings' ][] = + '' . + __( 'Dismiss this warning', $this->domain ) . ''; } if( !empty( $this->action_links[ 'warnings' ] ) && is_array( $this->action_links[ 'warnings' ] ) ) { $message .= '

' . implode( ' | ', $this->action_links[ 'warnings' ] ) . '

'; @@ -199,7 +205,11 @@ public function admin_notices() { $message = sprintf( __( '

%s is active, but has the following notices:

%s', $this->domain ), $this->name, $message ); } if( $this->dismiss ) { - $this->action_links[ 'messages' ][] = '' . __( 'Dismiss this notice', $this->domain ) . ''; + $this->action_links[ 'messages' ][] = + '' . + __( 'Dismiss this notice', $this->domain ) . ''; } $message .= '

' . implode( ' | ', $this->action_links[ 'messages' ] ) . '

'; echo '
' . $message . '
'; @@ -221,20 +231,26 @@ public function admin_notices() { * dismiss the notice ajax callback * @throws \Exception */ - public function dismiss_notices(){ + public function dismiss_notices() { + check_ajax_referer('ud_dismiss'); + $response = array( 'success' => '0', 'error' => __( 'There was an error in request.', $this->domain ), ); + $error = false; - if( empty($_POST['key']) ) { + $option_key = isset($_POST['key']) ? sanitize_key($_POST['key']) : ''; + + if ( strpos($option_key, 'dismissed_') !== 0 ) { $response['error'] = __( 'Invalid key', $this->domain ); $error = true; } - if ( ! $error && update_option( ( $_POST['key'] ), time() ) ) { + if ( !$error && update_option( $option_key, time() ) ) { $response['success'] = '1'; + $response['error'] = null; } wp_send_json( $response ); diff --git a/vendor/udx/lib-wp-bootstrap/static/scripts/ud-dismiss.js b/vendor/udx/lib-wp-bootstrap/static/scripts/ud-dismiss.js index 8d248e79a..fa7edb809 100644 --- a/vendor/udx/lib-wp-bootstrap/static/scripts/ud-dismiss.js +++ b/vendor/udx/lib-wp-bootstrap/static/scripts/ud-dismiss.js @@ -11,6 +11,7 @@ jQuery( document ).ready( function () { var data = { action: 'ud_dismiss', key: _this.data('key'), + _ajax_nonce: _this.data('nonce'), } jQuery.post( _ud_vars.ajaxurl, data, function ( result_data ) { diff --git a/wp-stateless-media.php b/wp-stateless-media.php index 9808ff211..7fde37c46 100644 --- a/wp-stateless-media.php +++ b/wp-stateless-media.php @@ -4,7 +4,7 @@ * Plugin URI: https://stateless.udx.io/ * Description: Upload and serve your WordPress media files from Google Cloud Storage. * Author: UDX - * Version: 3.4.0 + * Version: 3.4.1 * Text Domain: stateless-media * Author URI: https://www.udx.io *