Skip to content

Commit 6421202

Browse files
sirrealDAreRodz
authored andcommitted
Interactivity API: Prevent non-object state from being added (#59886)
Ensure that `state` is an object when creating a store for a given namespace. `store.state` is expected to be an object. There is code that prevents state from being updated if it is not an object, but it's possible to set the state to a non-object initially, which breaks subsequent updates. Co-authored-by: sirreal <jonsurrell@git.wordpress.org> Co-authored-by: DAreRodz <darerodz@git.wordpress.org>
1 parent ce4250a commit 6421202

File tree

5 files changed

+22
-7
lines changed

5 files changed

+22
-7
lines changed

packages/e2e-tests/plugins/interactive-blocks/store/render.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22
/**
3-
* HTML for testing the directive `data-wp-bind`.
3+
* HTML for testing the `store` function.
44
*
55
* @package gutenberg-test-interactive-blocks
66
*/
@@ -9,6 +9,7 @@
99
?>
1010

1111
<div data-wp-interactive="test/store">
12+
<div data-wp-text="state.0" data-testid="state-0"></div>
1213
<div
1314
data-testid="non-plain object"
1415
data-wp-text="state.isNotProxified"

packages/e2e-tests/plugins/interactive-blocks/store/view.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,21 @@
33
*/
44
import { store, getElement } from '@wordpress/interactivity';
55

6+
// A non-object state should never be allowed.
7+
store( 'test/store', { state: [ 'wrong' ] } );
68

79
const { state } = store( 'test/store', {
810
state: {
11+
0: 'right',
912
get isNotProxified() {
1013
const { ref } = getElement();
1114
return state.elementRef === ref;
12-
}
15+
},
1316
},
1417
callbacks: {
1518
init() {
1619
const { ref } = getElement();
1720
state.elementRef = ref; // HTMLElement
18-
}
19-
}
20-
} )
21+
},
22+
},
23+
} );

packages/interactivity/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Bug Fixes
66

7+
- Prevent non-objects from being set in store state. ([#59886](https://github.com/WordPress/gutenberg/pull/59886))
78
- Ensure that stores are available for subscription before hydration. ([#59842](https://github.com/WordPress/gutenberg/pull/59842))
89
- Ensure scope is restored when catching exceptions thrown in async generator actions. ([#59708](https://github.com/WordPress/gutenberg/pull/59708))
910

packages/interactivity/src/store.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,10 @@ export function store(
274274
if ( lock !== universalUnlock ) {
275275
storeLocks.set( namespace, lock );
276276
}
277-
const rawStore = { state: deepSignal( state ), ...block };
277+
const rawStore = {
278+
state: deepSignal( isObject( state ) ? state : {} ),
279+
...block,
280+
};
278281
const proxiedStore = new Proxy( rawStore, handlers );
279282
rawStores.set( namespace, rawStore );
280283
stores.set( namespace, proxiedStore );

test/e2e/specs/interactivity/store.spec.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
import { test, expect } from './fixtures';
55

6-
test.describe( 'data-wp-bind', () => {
6+
test.describe( 'store', () => {
77
test.beforeAll( async ( { interactivityUtils: utils } ) => {
88
await utils.activatePlugins();
99
await utils.addPostWithBlock( 'test/store' );
@@ -22,4 +22,11 @@ test.describe( 'data-wp-bind', () => {
2222
const el = page.getByTestId( 'non-plain object' );
2323
await expect( el ).toHaveText( 'true' );
2424
} );
25+
26+
test( 'Ensures that state cannot be set to a non-object', async ( {
27+
page,
28+
} ) => {
29+
const element = page.getByTestId( 'state-0' );
30+
await expect( element ).toHaveText( 'right' );
31+
} );
2532
} );

0 commit comments

Comments
 (0)