Guarded ensureScrollValueMonitoring against some malicious script on the Internet overriding native document.createEvent (fixes #6887) (#7621)
Mateusz Burzyński committed
Aug 31, 2016 at 16:25 UTC
51476de9134f1a9d060dfe7566a1c752b68b381f
2 files changed
+30
-2
src/renderers/dom/client/ReactBrowserEventEmitter.js
+14
-2
@@ -344,6 +344,19 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
344
);
345
},
346
347
+ /**
348
+ * Protect against document.createEvent() returning null
349
+ * Some popup blocker extensions appear to do this:
350
+ * https://github.com/facebook/react/issues/6887
351
+ */
352
+ supportsEventPageXY: function() {
353
+ if (!document.createEvent) {
354
+ return false;
355
+ }
356
+ var ev = document.createEvent('MouseEvent');
357
+ return ev != null && 'pageX' in ev;
358
+ },
359
+
360
/**
361
* Listens to window scroll and resize events. We cache scroll values so that
362
* application code can access them without triggering reflows.
@@ -357,8 +370,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
370
*/
371
ensureScrollValueMonitoring: function() {
372
if (hasEventPageXY === undefined) {
360
- hasEventPageXY =
361
- document.createEvent && 'pageX' in document.createEvent('MouseEvent');
373
+ hasEventPageXY = ReactBrowserEventEmitter.supportsEventPageXY();
374
}
375
if (!hasEventPageXY && !isMonitoringScrollValue) {
376
var refresh = ViewportMetrics.refreshScrollValues;
src/renderers/dom/client/__tests__/ReactBrowserEventEmitter-test.js
+16
@@ -452,4 +452,20 @@ describe('ReactBrowserEventEmitter', function() {
452
expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
453
});
454
455
+ it('should not crash ensureScrollValueMonitoring when createEvent returns null', function() {
456
+ var originalCreateEvent = document.createEvent;
457
+ document.createEvent = function() {
458
+ return null;
459
+ };
460
+ spyOn(document, 'createEvent');
461
+
462
+ try {
463
+ var hasEventPageXY = ReactBrowserEventEmitter.supportsEventPageXY();
464
+ expect(document.createEvent.calls.count()).toBe(1);
465
+ expect(hasEventPageXY).toBe(false);
466
+ } finally {
467
+ document.createEvent = originalCreateEvent;
468
+ }
469
+ });
470
+
471
});