From d8f439c33514fdb5c9c5cd5d924b96a4fb8507ea Mon Sep 17 00:00:00 2001 From: "Dominik Schilling (ocean90)" Date: Mon, 6 Apr 2015 15:09:21 +0000 Subject: [PATCH] Customizer: Refresh nonces when a session expires and the user logs in again. This was broken since 4.0 and the introduction of user session tokens. The nonces are now tied to session tokens as opposed to user IDs, and thus they change with each re-login. Custom nonces can be added through the `customize_refresh_nonces` filter. On a successful refresh request the JavaScript API will trigger a `nonce-refresh` event. See widget's update nonce as an example. props westonruter for initial patch. fixes #31294. git-svn-id: https://develop.svn.wordpress.org/trunk@32054 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/js/customize-controls.js | 50 +++++++++++++++++-- src/wp-admin/js/customize-widgets.js | 5 ++ .../class-wp-customize-manager.php | 35 +++++++++++-- .../class-wp-customize-widgets.php | 15 ++++++ 4 files changed, 97 insertions(+), 8 deletions(-) diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js index e35ec4fdd8..4f04de4c0f 100644 --- a/src/wp-admin/js/customize-controls.js +++ b/src/wp-admin/js/customize-controls.js @@ -2358,11 +2358,23 @@ messenger.targetWindow( iframe[0].contentWindow ); - messenger.bind( 'login', function() { - iframe.remove(); - messenger.destroy(); - delete previewer._login; - deferred.resolve(); + messenger.bind( 'login', function () { + var refreshNonces = previewer.refreshNonces(); + + refreshNonces.always( function() { + iframe.remove(); + messenger.destroy(); + delete previewer._login; + }); + + refreshNonces.done( function() { + deferred.resolve(); + }); + + refreshNonces.fail( function() { + previewer.cheatin(); + deferred.reject(); + }); }); return this._login; @@ -2370,6 +2382,28 @@ cheatin: function() { $( document.body ).empty().addClass('cheatin').append( '

' + api.l10n.cheatin + '

' ); + }, + + refreshNonces: function() { + var request, deferred = $.Deferred(); + + deferred.promise(); + + request = wp.ajax.post( 'customize_refresh_nonces', { + wp_customize: 'on', + theme: api.settings.theme.stylesheet + }); + + request.done( function( response ) { + api.trigger( 'nonce-refresh', response ); + deferred.resolve(); + }); + + request.fail( function() { + deferred.reject(); + }); + + return deferred; } }); @@ -2538,6 +2572,12 @@ $.extend( this.nonce, nonce ); }); + // Refresh the nonces if login sends updated nonces over. + api.bind( 'nonce-refresh', function( nonce ) { + $.extend( api.settings.nonce, nonce ); + $.extend( api.previewer.nonce, nonce ); + }); + // Create Settings $.each( api.settings.settings, function( id, data ) { api.create( id, id, data.value, { diff --git a/src/wp-admin/js/customize-widgets.js b/src/wp-admin/js/customize-widgets.js index 8134a984d3..20c695b621 100644 --- a/src/wp-admin/js/customize-widgets.js +++ b/src/wp-admin/js/customize-widgets.js @@ -1898,6 +1898,11 @@ sidebar_widgets: api.Widgets.SidebarControl }); + // Refresh the nonce if login sends updated nonces over. + api.bind( 'nonce-refresh', function( nonces ) { + api.Widgets.data.nonce = nonces['update-widget']; + }); + /** * Init Customizer for widgets. */ diff --git a/src/wp-includes/class-wp-customize-manager.php b/src/wp-includes/class-wp-customize-manager.php index d24c283a4b..9fadd741c2 100644 --- a/src/wp-includes/class-wp-customize-manager.php +++ b/src/wp-includes/class-wp-customize-manager.php @@ -91,8 +91,8 @@ final class WP_Customize_Manager { add_filter( 'wp_die_handler', array( $this, 'wp_die_handler' ) ); - add_action( 'setup_theme', array( $this, 'setup_theme' ) ); - add_action( 'wp_loaded', array( $this, 'wp_loaded' ) ); + add_action( 'setup_theme', array( $this, 'setup_theme' ) ); + add_action( 'wp_loaded', array( $this, 'wp_loaded' ) ); // Run wp_redirect_status late to make sure we override the status last. add_action( 'wp_redirect_status', array( $this, 'wp_redirect_status' ), 1000 ); @@ -105,7 +105,8 @@ final class WP_Customize_Manager { remove_action( 'admin_init', '_maybe_update_plugins' ); remove_action( 'admin_init', '_maybe_update_themes' ); - add_action( 'wp_ajax_customize_save', array( $this, 'save' ) ); + add_action( 'wp_ajax_customize_save', array( $this, 'save' ) ); + add_action( 'wp_ajax_customize_refresh_nonces', array( $this, 'refresh_nonces' ) ); add_action( 'customize_register', array( $this, 'register_controls' ) ); add_action( 'customize_register', array( $this, 'register_dynamic_settings' ), 11 ); // allow code to create settings first @@ -783,6 +784,34 @@ final class WP_Customize_Manager { wp_send_json_success( $response ); } + /** + * Refresh nonces for the current preview. + * + * @since 4.2.0 + */ + public function refresh_nonces() { + if ( ! $this->is_preview() ) { + wp_send_json_error( 'not_preview' ); + } + + $nonces = array( + 'save' => wp_create_nonce( 'save-customize_' . $this->get_stylesheet() ), + 'preview' => wp_create_nonce( 'preview-customize_' . $this->get_stylesheet() ), + ); + + /** + * Filter nonces for a customize_refresh_nonces AJAX request. + * + * @since 4.2.0 + * + * @param array $nonces Array of refreshed nonces for save and + * preview actions. + * @param WP_Customize_Manager $this WP_Customize_Manager instance. + */ + $nonces = apply_filters( 'customize_refresh_nonces', $nonces, $this ); + wp_send_json_success( $nonces ); + } + /** * Add a customize setting. * diff --git a/src/wp-includes/class-wp-customize-widgets.php b/src/wp-includes/class-wp-customize-widgets.php index 966c853f9c..fe54d4cfd2 100644 --- a/src/wp-includes/class-wp-customize-widgets.php +++ b/src/wp-includes/class-wp-customize-widgets.php @@ -95,6 +95,7 @@ final class WP_Customize_Widgets { add_action( 'customize_controls_print_footer_scripts', array( $this, 'print_footer_scripts' ) ); add_action( 'customize_controls_print_footer_scripts', array( $this, 'output_widget_control_templates' ) ); add_action( 'customize_preview_init', array( $this, 'customize_preview_init' ) ); + add_filter( 'customize_refresh_nonces', array( $this, 'refresh_nonces' ) ); add_action( 'dynamic_sidebar', array( $this, 'tally_rendered_widgets' ) ); add_filter( 'is_active_sidebar', array( $this, 'tally_sidebars_via_is_active_sidebar_calls' ), 10, 2 ); @@ -888,6 +889,20 @@ final class WP_Customize_Widgets { add_action( 'wp_footer', array( $this, 'export_preview_data' ), 20 ); } + /** + * Refresh nonce for widget updates. + * + * @since 4.2.0 + * @access public + * + * @param array $nonces Array of nonces. + * @return array $nonces Array of nonces. + */ + public function refresh_nonces( $nonces ) { + $nonces['update-widget'] = wp_create_nonce( 'update-widget' ); + return $nonces; + } + /** * When previewing, make sure the proper previewing widgets are used. *