Compare commits
3 Commits
pr32012
...
16.4.2-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54adb2674a | ||
|
|
d922ed2cf2 | ||
|
|
5b19684fc3 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"version": "16.4.1",
|
||||
"version": "16.4.2",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "create-subscription",
|
||||
"description": "utility for subscribing to external data sources inside React components",
|
||||
"version": "16.4.1",
|
||||
"version": "16.4.2",
|
||||
"repository": "facebook/react",
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "react-art",
|
||||
"description": "React ART is a JavaScript library for drawing vector graphics using React. It provides declarative and reactive bindings to the ART library. Using the same declarative API you can render the output to either Canvas, SVG or VML (IE8).",
|
||||
"version": "16.4.1",
|
||||
"version": "16.4.2",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-dom",
|
||||
"version": "16.4.1",
|
||||
"version": "16.4.2",
|
||||
"description": "React package for working with the DOM.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
|
||||
@@ -554,39 +554,174 @@ describe('ReactDOMComponent', () => {
|
||||
expect(stubStyle.color).toEqual('green');
|
||||
});
|
||||
|
||||
it('should reject attribute key injection attack on markup', () => {
|
||||
it('should reject attribute key injection attack on markup for regular DOM (SSR)', () => {
|
||||
expect(() => {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const container = document.createElement('div');
|
||||
const element = React.createElement(
|
||||
const element1 = React.createElement(
|
||||
'div',
|
||||
{'blah" onclick="beevil" noise="hi': 'selected'},
|
||||
null,
|
||||
);
|
||||
const element2 = React.createElement(
|
||||
'div',
|
||||
{'></div><script>alert("hi")</script>': 'selected'},
|
||||
null,
|
||||
);
|
||||
let result1 = ReactDOMServer.renderToString(element1);
|
||||
let result2 = ReactDOMServer.renderToString(element2);
|
||||
expect(result1.toLowerCase()).not.toContain('onclick');
|
||||
expect(result2.toLowerCase()).not.toContain('script');
|
||||
}
|
||||
}).toWarnDev([
|
||||
'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`',
|
||||
'Warning: Invalid attribute name: `></div><script>alert("hi")</script>`',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should reject attribute key injection attack on markup for custom elements (SSR)', () => {
|
||||
expect(() => {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const element1 = React.createElement(
|
||||
'x-foo-component',
|
||||
{'blah" onclick="beevil" noise="hi': 'selected'},
|
||||
null,
|
||||
);
|
||||
ReactDOM.render(element, container);
|
||||
const element2 = React.createElement(
|
||||
'x-foo-component',
|
||||
{'></x-foo-component><script>alert("hi")</script>': 'selected'},
|
||||
null,
|
||||
);
|
||||
let result1 = ReactDOMServer.renderToString(element1);
|
||||
let result2 = ReactDOMServer.renderToString(element2);
|
||||
expect(result1.toLowerCase()).not.toContain('onclick');
|
||||
expect(result2.toLowerCase()).not.toContain('script');
|
||||
}
|
||||
}).toWarnDev(
|
||||
}).toWarnDev([
|
||||
'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`',
|
||||
);
|
||||
'Warning: Invalid attribute name: `></x-foo-component><script>alert("hi")</script>`',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should reject attribute key injection attack on update', () => {
|
||||
it('should reject attribute key injection attack on mount for regular DOM', () => {
|
||||
expect(() => {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const container = document.createElement('div');
|
||||
ReactDOM.render(
|
||||
React.createElement(
|
||||
'div',
|
||||
{'blah" onclick="beevil" noise="hi': 'selected'},
|
||||
null,
|
||||
),
|
||||
container,
|
||||
);
|
||||
expect(container.firstChild.attributes.length).toBe(0);
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
ReactDOM.render(
|
||||
React.createElement(
|
||||
'div',
|
||||
{'></div><script>alert("hi")</script>': 'selected'},
|
||||
null,
|
||||
),
|
||||
container,
|
||||
);
|
||||
expect(container.firstChild.attributes.length).toBe(0);
|
||||
}
|
||||
}).toWarnDev([
|
||||
'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`',
|
||||
'Warning: Invalid attribute name: `></div><script>alert("hi")</script>`',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should reject attribute key injection attack on mount for custom elements', () => {
|
||||
expect(() => {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const container = document.createElement('div');
|
||||
ReactDOM.render(
|
||||
React.createElement(
|
||||
'x-foo-component',
|
||||
{'blah" onclick="beevil" noise="hi': 'selected'},
|
||||
null,
|
||||
),
|
||||
container,
|
||||
);
|
||||
expect(container.firstChild.attributes.length).toBe(0);
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
ReactDOM.render(
|
||||
React.createElement(
|
||||
'x-foo-component',
|
||||
{'></x-foo-component><script>alert("hi")</script>': 'selected'},
|
||||
null,
|
||||
),
|
||||
container,
|
||||
);
|
||||
expect(container.firstChild.attributes.length).toBe(0);
|
||||
}
|
||||
}).toWarnDev([
|
||||
'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`',
|
||||
'Warning: Invalid attribute name: `></x-foo-component><script>alert("hi")</script>`',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should reject attribute key injection attack on update for regular DOM', () => {
|
||||
expect(() => {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const container = document.createElement('div');
|
||||
const beforeUpdate = React.createElement('div', {}, null);
|
||||
ReactDOM.render(beforeUpdate, container);
|
||||
ReactDOM.render(
|
||||
React.createElement(
|
||||
'div',
|
||||
{'blah" onclick="beevil" noise="hi': 'selected'},
|
||||
null,
|
||||
),
|
||||
container,
|
||||
);
|
||||
expect(container.firstChild.attributes.length).toBe(0);
|
||||
ReactDOM.render(
|
||||
React.createElement(
|
||||
'div',
|
||||
{'></div><script>alert("hi")</script>': 'selected'},
|
||||
null,
|
||||
),
|
||||
container,
|
||||
);
|
||||
expect(container.firstChild.attributes.length).toBe(0);
|
||||
}
|
||||
}).toWarnDev([
|
||||
'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`',
|
||||
'Warning: Invalid attribute name: `></div><script>alert("hi")</script>`',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should reject attribute key injection attack on update for custom elements', () => {
|
||||
expect(() => {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const container = document.createElement('div');
|
||||
const beforeUpdate = React.createElement('x-foo-component', {}, null);
|
||||
ReactDOM.render(beforeUpdate, container);
|
||||
|
||||
const afterUpdate = React.createElement(
|
||||
'x-foo-component',
|
||||
{'blah" onclick="beevil" noise="hi': 'selected'},
|
||||
null,
|
||||
ReactDOM.render(
|
||||
React.createElement(
|
||||
'x-foo-component',
|
||||
{'blah" onclick="beevil" noise="hi': 'selected'},
|
||||
null,
|
||||
),
|
||||
container,
|
||||
);
|
||||
ReactDOM.render(afterUpdate, container);
|
||||
expect(container.firstChild.attributes.length).toBe(0);
|
||||
ReactDOM.render(
|
||||
React.createElement(
|
||||
'x-foo-component',
|
||||
{'></x-foo-component><script>alert("hi")</script>': 'selected'},
|
||||
null,
|
||||
),
|
||||
container,
|
||||
);
|
||||
expect(container.firstChild.attributes.length).toBe(0);
|
||||
}
|
||||
}).toWarnDev(
|
||||
}).toWarnDev([
|
||||
'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`',
|
||||
);
|
||||
'Warning: Invalid attribute name: `></x-foo-component><script>alert("hi")</script>`',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should update arbitrary attributes for tags containing dashes', () => {
|
||||
|
||||
@@ -174,6 +174,19 @@ describe('ReactDOMServer', () => {
|
||||
(__DEV__ ? '\n in iframe (at **)' : ''),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not crash on poisoned hasOwnProperty', () => {
|
||||
let html;
|
||||
expect(
|
||||
() =>
|
||||
(html = ReactDOMServer.renderToString(
|
||||
<div hasOwnProperty="poison">
|
||||
<span unknown="test" />
|
||||
</div>,
|
||||
)),
|
||||
).toWarnDev(['React does not recognize the `hasOwnProperty` prop']);
|
||||
expect(html).toContain('<span unknown="test">');
|
||||
});
|
||||
});
|
||||
|
||||
describe('renderToStaticMarkup', () => {
|
||||
|
||||
@@ -60,9 +60,10 @@ export function createMarkupForProperty(name: string, value: mixed): string {
|
||||
} else {
|
||||
return attributeName + '=' + quoteAttributeValueForBrowser(value);
|
||||
}
|
||||
} else {
|
||||
} else if (isAttributeNameSafe(name)) {
|
||||
return name + '=' + quoteAttributeValueForBrowser(value);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -308,6 +308,7 @@ function processContext(type, context) {
|
||||
return maskedContext;
|
||||
}
|
||||
|
||||
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
const STYLE = 'style';
|
||||
const RESERVED_PROPS = {
|
||||
children: null,
|
||||
@@ -327,7 +328,7 @@ function createOpenTagMarkup(
|
||||
let ret = '<' + tagVerbatim;
|
||||
|
||||
for (const propKey in props) {
|
||||
if (!props.hasOwnProperty(propKey)) {
|
||||
if (!hasOwnProperty.call(props, propKey)) {
|
||||
continue;
|
||||
}
|
||||
let propValue = props[propKey];
|
||||
|
||||
5
packages/react-dom/src/shared/DOMProperty.js
vendored
5
packages/react-dom/src/shared/DOMProperty.js
vendored
@@ -66,14 +66,15 @@ export const VALID_ATTRIBUTE_NAME_REGEX = new RegExp(
|
||||
'^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$',
|
||||
);
|
||||
|
||||
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
const illegalAttributeNameCache = {};
|
||||
const validatedAttributeNameCache = {};
|
||||
|
||||
export function isAttributeNameSafe(attributeName: string): boolean {
|
||||
if (validatedAttributeNameCache.hasOwnProperty(attributeName)) {
|
||||
if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) {
|
||||
return true;
|
||||
}
|
||||
if (illegalAttributeNameCache.hasOwnProperty(attributeName)) {
|
||||
if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) {
|
||||
return false;
|
||||
}
|
||||
if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-is",
|
||||
"version": "16.4.1",
|
||||
"version": "16.4.2",
|
||||
"description": "Brand checking of React Elements.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-test-renderer",
|
||||
"version": "16.4.1",
|
||||
"version": "16.4.2",
|
||||
"description": "React package for snapshot testing.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
@@ -18,7 +18,7 @@
|
||||
"fbjs": "^0.8.16",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.0",
|
||||
"react-is": "^16.4.1"
|
||||
"react-is": "^16.4.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"keywords": [
|
||||
"react"
|
||||
],
|
||||
"version": "16.4.1",
|
||||
"version": "16.4.2",
|
||||
"homepage": "https://reactjs.org/",
|
||||
"bugs": "https://github.com/facebook/react/issues",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
'use strict';
|
||||
|
||||
// TODO: this is special because it gets imported during build.
|
||||
module.exports = '16.4.1';
|
||||
module.exports = '16.4.2';
|
||||
|
||||
@@ -46,29 +46,29 @@
|
||||
"filename": "react-dom.development.js",
|
||||
"bundleType": "UMD_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 641505,
|
||||
"gzip": 149286
|
||||
"size": 641575,
|
||||
"gzip": 149303
|
||||
},
|
||||
{
|
||||
"filename": "react-dom.production.min.js",
|
||||
"bundleType": "UMD_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 96507,
|
||||
"gzip": 31258
|
||||
"size": 96528,
|
||||
"gzip": 31268
|
||||
},
|
||||
{
|
||||
"filename": "react-dom.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 625496,
|
||||
"gzip": 145193
|
||||
"size": 625566,
|
||||
"gzip": 145209
|
||||
},
|
||||
{
|
||||
"filename": "react-dom.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 94969,
|
||||
"gzip": 30225
|
||||
"size": 94990,
|
||||
"gzip": 30219
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOM-dev.js",
|
||||
@@ -110,7 +110,7 @@
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 9913,
|
||||
"gzip": 3696
|
||||
"gzip": 3697
|
||||
},
|
||||
{
|
||||
"filename": "ReactTestUtils-dev.js",
|
||||
@@ -124,7 +124,7 @@
|
||||
"bundleType": "UMD_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 62921,
|
||||
"gzip": 16559
|
||||
"gzip": 16560
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-unstable-native-dependencies.production.min.js",
|
||||
@@ -165,29 +165,29 @@
|
||||
"filename": "react-dom-server.browser.development.js",
|
||||
"bundleType": "UMD_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 105006,
|
||||
"gzip": 27524
|
||||
"size": 105186,
|
||||
"gzip": 27547
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-server.browser.production.min.js",
|
||||
"bundleType": "UMD_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 15463,
|
||||
"gzip": 5917
|
||||
"size": 15521,
|
||||
"gzip": 5938
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-server.browser.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 94052,
|
||||
"gzip": 25217
|
||||
"size": 94232,
|
||||
"gzip": 25238
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-server.browser.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 14810,
|
||||
"gzip": 5665
|
||||
"size": 14866,
|
||||
"gzip": 5690
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOMServer-dev.js",
|
||||
@@ -207,22 +207,22 @@
|
||||
"filename": "react-dom-server.node.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 96020,
|
||||
"gzip": 25767
|
||||
"size": 96200,
|
||||
"gzip": 25790
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-server.node.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 15634,
|
||||
"gzip": 5964
|
||||
"size": 15690,
|
||||
"gzip": 5986
|
||||
},
|
||||
{
|
||||
"filename": "react-art.development.js",
|
||||
"bundleType": "UMD_DEV",
|
||||
"packageName": "react-art",
|
||||
"size": 417844,
|
||||
"gzip": 93214
|
||||
"gzip": 93213
|
||||
},
|
||||
{
|
||||
"filename": "react-art.production.min.js",
|
||||
@@ -369,7 +369,7 @@
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-noop-renderer",
|
||||
"size": 6829,
|
||||
"gzip": 2631
|
||||
"gzip": 2632
|
||||
},
|
||||
{
|
||||
"filename": "react-reconciler.development.js",
|
||||
@@ -404,7 +404,7 @@
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-reconciler",
|
||||
"size": 11847,
|
||||
"gzip": 3642
|
||||
"gzip": 3643
|
||||
},
|
||||
{
|
||||
"filename": "react-reconciler-reflection.production.min.js",
|
||||
@@ -446,7 +446,7 @@
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-is",
|
||||
"size": 4596,
|
||||
"gzip": 1264
|
||||
"gzip": 1265
|
||||
},
|
||||
{
|
||||
"filename": "react-is.production.min.js",
|
||||
@@ -509,21 +509,21 @@
|
||||
"bundleType": "FB_WWW_PROD",
|
||||
"packageName": "react",
|
||||
"size": 13708,
|
||||
"gzip": 3835
|
||||
"gzip": 3836
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOM-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 634902,
|
||||
"gzip": 144512
|
||||
"size": 634972,
|
||||
"gzip": 144538
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOM-prod.js",
|
||||
"bundleType": "FB_WWW_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 275897,
|
||||
"gzip": 51771
|
||||
"size": 275965,
|
||||
"gzip": 51777
|
||||
},
|
||||
{
|
||||
"filename": "ReactTestUtils-dev.js",
|
||||
@@ -550,15 +550,15 @@
|
||||
"filename": "ReactDOMServer-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 97859,
|
||||
"gzip": 25094
|
||||
"size": 98039,
|
||||
"gzip": 25126
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOMServer-prod.js",
|
||||
"bundleType": "FB_WWW_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 32295,
|
||||
"gzip": 7922
|
||||
"size": 32512,
|
||||
"gzip": 7964
|
||||
},
|
||||
{
|
||||
"filename": "ReactART-dev.js",
|
||||
@@ -579,14 +579,14 @@
|
||||
"bundleType": "RN_FB_DEV",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 468596,
|
||||
"gzip": 102411
|
||||
"gzip": 102412
|
||||
},
|
||||
{
|
||||
"filename": "ReactNativeRenderer-prod.js",
|
||||
"bundleType": "RN_FB_PROD",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 210858,
|
||||
"gzip": 36787
|
||||
"gzip": 36788
|
||||
},
|
||||
{
|
||||
"filename": "ReactNativeRenderer-dev.js",
|
||||
@@ -614,7 +614,7 @@
|
||||
"bundleType": "RN_FB_PROD",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 190842,
|
||||
"gzip": 33372
|
||||
"gzip": 33376
|
||||
},
|
||||
{
|
||||
"filename": "ReactFabric-dev.js",
|
||||
@@ -712,14 +712,14 @@
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-noop-renderer",
|
||||
"size": 6851,
|
||||
"gzip": 2637
|
||||
"gzip": 2638
|
||||
},
|
||||
{
|
||||
"filename": "react-dom.profiling.min.js",
|
||||
"bundleType": "NODE_PROFILING",
|
||||
"packageName": "react-dom",
|
||||
"size": 95896,
|
||||
"gzip": 30574
|
||||
"size": 95917,
|
||||
"gzip": 30579
|
||||
},
|
||||
{
|
||||
"filename": "ReactNativeRenderer-profiling.js",
|
||||
|
||||
Reference in New Issue
Block a user