33 */
44import apiFetch from '@wordpress/api-fetch' ;
55
6- // @ts -ignore wcStoreApiNonce is window global
7- // Cache for the initial nonce initialized from hydration.
8- let nonce = wcStoreApiNonce || '' ;
6+ // Stores the current nonce for the middleware.
7+ let currentNonce = '' ;
8+ let currentTimestamp = 0 ;
9+
10+ try {
11+ const storedNonceValue = window . localStorage . getItem ( 'storeApiNonce' ) ;
12+ const storedNonce = storedNonceValue ? JSON . parse ( storedNonceValue ) : { } ;
13+ currentNonce = storedNonce ?. nonce || '' ;
14+ currentTimestamp = storedNonce ?. timestamp || 0 ;
15+ } catch {
16+ // We can ignore an error from JSON parse.
17+ }
918
1019/**
1120 * Returns whether or not this is a non GET wc/store API request.
@@ -28,12 +37,44 @@ const isStoreApiGetRequest = ( options ) => {
2837 * @param {Object } headers Headers object.
2938 */
3039const setNonce = ( headers ) => {
31- const newNonce = headers ?. get ( 'X-WC-Store-API-Nonce' ) ;
32- if ( newNonce ) {
33- nonce = newNonce ;
40+ const nonce = headers ?. get ( 'X-WC-Store-API-Nonce' ) || '' ;
41+ const timestamp = headers ?. get ( 'X-WC-Store-API-Nonce-Timestamp' ) || 0 ;
42+
43+ if ( nonce ) {
44+ updateNonce ( nonce , timestamp ) ;
3445 }
3546} ;
3647
48+ /**
49+ * Updates the stored nonce within localStorage so it is persisted between page loads.
50+ *
51+ * @param {string } nonce Incoming nonce string.
52+ * @param {number } timestamp Timestamp from server of nonce.
53+ */
54+ const updateNonce = ( nonce , timestamp ) => {
55+ // If the "new" nonce matches the current nonce, we don't need to update.
56+ if ( nonce === currentNonce ) {
57+ return ;
58+ }
59+
60+ // Only update the nonce if newer. It might be coming from cache.
61+ if ( currentTimestamp && timestamp < currentTimestamp ) {
62+ return ;
63+ }
64+
65+ currentNonce = nonce ;
66+ currentTimestamp = timestamp || Date . now ( ) / 1000 ; // Convert ms to seconds to match php time()
67+
68+ // Update the persisted values.
69+ window . localStorage . setItem (
70+ 'storeApiNonce' ,
71+ JSON . stringify ( {
72+ nonce : currentNonce ,
73+ timestamp : currentTimestamp ,
74+ } )
75+ ) ;
76+ } ;
77+
3778/**
3879 * Nonce middleware which updates the nonce after a request, if given.
3980 *
@@ -47,11 +88,15 @@ const storeNonceMiddleware = ( options, next ) => {
4788 const existingHeaders = options . headers || { } ;
4889 options . headers = {
4990 ...existingHeaders ,
50- 'X-WC-Store-API-Nonce' : nonce ,
91+ 'X-WC-Store-API-Nonce' : currentNonce ,
5192 } ;
5293 }
5394 return next ( options , next ) ;
5495} ;
5596
5697apiFetch . use ( storeNonceMiddleware ) ;
5798apiFetch . setNonce = setNonce ;
99+
100+ // @ts -ignore wcStoreApiNonce is window global cache for the initial nonce initialized from hydration.
101+ // @ts -ignore wcStoreApiNonceTimestamp is window global cache for the initial nonce initialized from hydration.
102+ updateNonce ( wcStoreApiNonce , wcStoreApiNonceTimestamp ) ;
0 commit comments