From be29e265c57349865e891e6bb4af23cb2ed6c930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 31 Aug 2016 15:05:44 +0200 Subject: [PATCH] Guarded ensureScrollValueMonitoring against some malicious script on the Internet overriding native document.createEvent (fixes #6887) --- .../dom/client/ReactBrowserEventEmitter.js | 16 ++++++++++++++-- .../__tests__/ReactBrowserEventEmitter-test.js | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/renderers/dom/client/ReactBrowserEventEmitter.js b/src/renderers/dom/client/ReactBrowserEventEmitter.js index 1b4b2be303ad5..0d6a3b7a46db7 100644 --- a/src/renderers/dom/client/ReactBrowserEventEmitter.js +++ b/src/renderers/dom/client/ReactBrowserEventEmitter.js @@ -344,6 +344,19 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, { ); }, + /** + * Protect against document.createEvent() returning null + * Some popup blocker extensions appear to do this: + * https://github.com/facebook/react/issues/6887 + */ + supportsEventPageXY: function() { + if (!document.createEvent) { + return false; + } + var ev = document.createEvent('MouseEvent'); + return ev != null && 'pageX' in ev; + }, + /** * Listens to window scroll and resize events. We cache scroll values so that * application code can access them without triggering reflows. @@ -357,8 +370,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, { */ ensureScrollValueMonitoring: function() { if (hasEventPageXY === undefined) { - hasEventPageXY = - document.createEvent && 'pageX' in document.createEvent('MouseEvent'); + hasEventPageXY = ReactBrowserEventEmitter.supportsEventPageXY(); } if (!hasEventPageXY && !isMonitoringScrollValue) { var refresh = ViewportMetrics.refreshScrollValues; diff --git a/src/renderers/dom/client/__tests__/ReactBrowserEventEmitter-test.js b/src/renderers/dom/client/__tests__/ReactBrowserEventEmitter-test.js index a2d4848ba426d..920dc48056fd5 100644 --- a/src/renderers/dom/client/__tests__/ReactBrowserEventEmitter-test.js +++ b/src/renderers/dom/client/__tests__/ReactBrowserEventEmitter-test.js @@ -452,4 +452,20 @@ describe('ReactBrowserEventEmitter', function() { expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT)); }); + it('should not crash ensureScrollValueMonitoring when createEvent returns null', function() { + var originalCreateEvent = document.createEvent; + document.createEvent = function() { + return null; + }; + spyOn(document, 'createEvent'); + + try { + var hasEventPageXY = ReactBrowserEventEmitter.supportsEventPageXY(); + expect(document.createEvent.calls.count()).toBe(1); + expect(hasEventPageXY).toBe(false); + } finally { + document.createEvent = originalCreateEvent; + } + }); + });