From 80c424900edf7a359e1d51900092e2cbb08f773b Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Thu, 21 Sep 2017 12:57:16 +0000 Subject: [PATCH] REST API JS Client: Improve nonce handling, refresh stale nonce on sync. Keep the nonce used for cookie based authentication fresh by pulling in and using any new nonce supplied in the response headers. * Enable passing nonce to init so each api/endpoint can use a unique nonce. * Store nonce for endpoint on endpointModel. * New model helper `nonce()` retrieves a model's routeModel nonce. * When a response header contains a nonce that doesn't match the stored nonce, replace it. Fixes #40422. git-svn-id: https://develop.svn.wordpress.org/trunk@41553 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/js/wp-api.js | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/js/wp-api.js b/src/wp-includes/js/wp-api.js index c6ff5a872f..31886d280b 100644 --- a/src/wp-includes/js/wp-api.js +++ b/src/wp-includes/js/wp-api.js @@ -793,19 +793,29 @@ model.unset( 'slug' ); } - if ( ! _.isUndefined( wpApiSettings.nonce ) && ! _.isNull( wpApiSettings.nonce ) ) { + if ( _.isFunction( model.nonce ) && ! _.isUndefined( model.nonce() ) && ! _.isNull( model.nonce() ) ) { beforeSend = options.beforeSend; // @todo enable option for jsonp endpoints // options.dataType = 'jsonp'; + // Include the nonce with requests. options.beforeSend = function( xhr ) { - xhr.setRequestHeader( 'X-WP-Nonce', wpApiSettings.nonce ); + xhr.setRequestHeader( 'X-WP-Nonce', model.nonce() ); if ( beforeSend ) { return beforeSend.apply( this, arguments ); } }; + + // Update the nonce when a new nonce is returned with the response. + options.complete = function( xhr ) { + var returnedNonce = xhr.getResponseHeader( 'X-WP-Nonce' ); + + if ( returnedNonce && _.isFunction( model.nonce ) && model.nonce() !== returnedNonce ) { + model.endpointModel.set( 'nonce', returnedNonce ); + } + }; } // Add '?force=true' to use delete method when required. @@ -1048,6 +1058,7 @@ defaults: { apiRoot: wpApiSettings.root, versionString: wp.api.versionString, + nonce: null, schema: null, models: {}, collections: {} @@ -1065,8 +1076,9 @@ model.schemaConstructed = deferred.promise(); model.schemaModel = new wp.api.models.Schema( null, { - apiRoot: model.get( 'apiRoot' ), - versionString: model.get( 'versionString' ) + apiRoot: model.get( 'apiRoot' ), + versionString: model.get( 'versionString' ), + nonce: model.get( 'nonce' ) } ); // When the model loads, resolve the promise. @@ -1238,6 +1250,13 @@ return url; }, + // Track nonces on the Endpoint 'routeModel'. + nonce: function() { + return routeModel.get( 'nonce' ); + }, + + endpointModel: routeModel, + // Include a reference to the original route object. route: modelRoute, @@ -1284,6 +1303,13 @@ return url; }, + // Track nonces at the Endpoint level. + nonce: function() { + return routeModel.get( 'nonce' ); + }, + + endpointModel: routeModel, + // Include a reference to the original route object. route: modelRoute, @@ -1405,6 +1431,7 @@ var endpoint, attributes = {}, deferred, promise; args = args || {}; + attributes.nonce = args.nonce || wpApiSettings.nonce || ''; attributes.apiRoot = args.apiRoot || wpApiSettings.root || '/wp-json'; attributes.versionString = args.versionString || wpApiSettings.versionString || 'wp/v2/'; attributes.schema = args.schema || null;