@samitouri / QOS-React / commits / f677bfc964

Fix __proto__ bug in ReactDOMSelect (#9536)

https://twitter.com/rauschma/status/857307345231249409

Ben Alpert committed Apr 29, 2017 at 08:23 UTC f677bfc964574053a41539fffae7891968c910a3
4 files changed +61 -4
scripts/fiber/tests-passing.txt
+2
@@ -1529,8 +1529,10 @@ src/renderers/dom/shared/wrappers/__tests__/ReactDOMSelect-test.js
1529 * should not control when using `defaultValue`
1530 * should allow setting `defaultValue` with multiple
1531 * should allow setting `value`
1532 +* should allow setting `value` to __proto__
1533 * should not throw with `value` and without children
1534 * should allow setting `value` with multiple
1535 +* should allow setting `value` to __proto__ with multiple
1536 * should not select other options automatically
1537 * should reset child options selected when they are changed and `value` is set
1538 * should allow setting `value` with `objectToString`
src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js
+3 -2
@@ -89,10 +89,11 @@ function updateOptions(
89 let selectedValues = (propValue: Array<string>);
90 let selectedValue = {};
91 for (let i = 0; i < selectedValues.length; i++) {
92 - selectedValue['' + selectedValues[i]] = true;
92 + // Prefix to avoid chaos with special keys.
93 + selectedValue['$' + selectedValues[i]] = true;
94 }
95 for (let i = 0; i < options.length; i++) {
95 - var selected = selectedValue.hasOwnProperty(options[i].value);
96 + var selected = selectedValue.hasOwnProperty('$' + options[i].value);
97 if (options[i].selected !== selected) {
98 options[i].selected = selected;
99 }
src/renderers/dom/shared/wrappers/__tests__/ReactDOMSelect-test.js
+53
@@ -128,6 +128,29 @@ describe('ReactDOMSelect', () => {
128 expect(node.value).toEqual('gorilla');
129 });
130
131 + it('should allow setting `value` to __proto__', () => {
132 + var stub = (
133 + <select value="__proto__" onChange={noop}>
134 + <option value="monkey">A monkey!</option>
135 + <option value="__proto__">A giraffe!</option>
136 + <option value="gorilla">A gorilla!</option>
137 + </select>
138 + );
139 + var options = stub.props.children;
140 + var container = document.createElement('div');
141 + stub = ReactDOM.render(stub, container);
142 + var node = ReactDOM.findDOMNode(stub);
143 +
144 + expect(node.value).toBe('__proto__');
145 +
146 + // Changing the `value` prop should change the selected option.
147 + ReactDOM.render(
148 + <select value="gorilla" onChange={noop}>{options}</select>,
149 + container,
150 + );
151 + expect(node.value).toEqual('gorilla');
152 + });
153 +
154 it('should not throw with `value` and without children', () => {
155 var stub = <select value="dummy" onChange={noop} />;
156
@@ -166,6 +189,36 @@ describe('ReactDOMSelect', () => {
189 expect(node.options[2].selected).toBe(false); // gorilla
190 });
191
192 + it('should allow setting `value` to __proto__ with multiple', () => {
193 + var stub = (
194 + <select multiple={true} value={['__proto__', 'gorilla']} onChange={noop}>
195 + <option value="monkey">A monkey!</option>
196 + <option value="__proto__">A __proto__!</option>
197 + <option value="gorilla">A gorilla!</option>
198 + </select>
199 + );
200 + var options = stub.props.children;
201 + var container = document.createElement('div');
202 + stub = ReactDOM.render(stub, container);
203 + var node = ReactDOM.findDOMNode(stub);
204 +
205 + expect(node.options[0].selected).toBe(false); // monkey
206 + expect(node.options[1].selected).toBe(true); // __proto__
207 + expect(node.options[2].selected).toBe(true); // gorilla
208 +
209 + // Changing the `value` prop should change the selected options.
210 + ReactDOM.render(
211 + <select multiple={true} value={['monkey']} onChange={noop}>
212 + {options}
213 + </select>,
214 + container,
215 + );
216 +
217 + expect(node.options[0].selected).toBe(true); // monkey
218 + expect(node.options[1].selected).toBe(false); // __proto__
219 + expect(node.options[2].selected).toBe(false); // gorilla
220 + });
221 +
222 it('should not select other options automatically', () => {
223 var stub = (
224 <select multiple={true} value={['12']} onChange={noop}>
src/renderers/dom/stack/client/wrappers/ReactDOMSelect.js
+3 -2
@@ -84,10 +84,11 @@ function updateOptions(inst, multiple, propValue) {
84 if (multiple) {
85 let selectedValue = {};
86 for (let i = 0; i < propValue.length; i++) {
87 - selectedValue['' + propValue[i]] = true;
87 + // Prefix to avoid chaos with special keys.
88 + selectedValue['$' + propValue[i]] = true;
89 }
90 for (let i = 0; i < options.length; i++) {
90 - var selected = selectedValue.hasOwnProperty(options[i].value);
91 + var selected = selectedValue.hasOwnProperty('$' + options[i].value);
92 if (options[i].selected !== selected) {
93 options[i].selected = selected;
94 }