Skip to content

Commit d539303

Browse files
authored
fix: Prevent iterating over SyntheticEvents (#1900)
1 parent 13909e6 commit d539303

File tree

4 files changed

+48
-5
lines changed

4 files changed

+48
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
## 4.6.3
6+
7+
- [utils] fix: Normalize value before recursively walking down the tree
8+
59
## 4.6.2
610

711
- [utils] fix: Preserve function prototype when filling

packages/utils/src/is.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,15 @@ export function isRegExp(wat: any): boolean {
138138
export function isNaN(wat: any): boolean {
139139
return wat !== wat;
140140
}
141+
142+
/**
143+
* Checks whether given value's type is a SyntheticEvent
144+
* {@link isSyntheticEvent}.
145+
*
146+
* @param wat A value to be checked.
147+
* @returns A boolean representing the result.
148+
*/
149+
export function isSyntheticEvent(wat: any): boolean {
150+
// tslint:disable-next-line:no-unsafe-any
151+
return isPlainObject(wat) && 'nativeEvent' in wat && 'preventDefault' in wat && 'stopPropagation' in wat;
152+
}

packages/utils/src/object.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { SentryWrappedFunction } from '@sentry/types';
2-
import { isArray, isNaN, isPlainObject, isPrimitive, isUndefined } from './is';
2+
import { isArray, isNaN, isPlainObject, isPrimitive, isSyntheticEvent, isUndefined } from './is';
33
import { Memo } from './memo';
44
import { truncate } from './string';
55

@@ -291,10 +291,6 @@ function normalizeValue(value: any, key?: any): any {
291291
return '[Document]';
292292
}
293293

294-
if (value instanceof Date) {
295-
return `[Date] ${value}`;
296-
}
297-
298294
if (value instanceof Error) {
299295
return objectifyError(value);
300296
}
@@ -304,6 +300,11 @@ function normalizeValue(value: any, key?: any): any {
304300
return Object.getPrototypeOf(value) ? value.constructor.name : 'Event';
305301
}
306302

303+
// React's SyntheticEvent thingy
304+
if (isSyntheticEvent(value)) {
305+
return '[SyntheticEvent]';
306+
}
307+
307308
if (isNaN(value)) {
308309
return '[NaN]';
309310
}
@@ -328,6 +329,12 @@ function normalizeValue(value: any, key?: any): any {
328329
export function decycle(obj: any, memo: Memo = new Memo()): any {
329330
// tslint:disable-next-line:no-unsafe-any
330331
const copy = isArray(obj) ? obj.slice() : isPlainObject(obj) ? assign({}, obj) : obj;
332+
const normalized = normalizeValue(obj);
333+
334+
// If an object was normalized to its string form, we should just bail out as theres no point in going down that branch
335+
if (typeof normalized === 'string') {
336+
return normalized;
337+
}
331338

332339
if (!isPrimitive(obj)) {
333340
if (memo.memoize(obj)) {

packages/utils/test/object.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,4 +587,24 @@ describe('safeNormalize()', () => {
587587
reason: '[Circular ~]',
588588
});
589589
});
590+
591+
test('normalizes value on every iteration of decycle and takes care of things like Reacts SyntheticEvents', () => {
592+
const obj = {
593+
foo: {
594+
nativeEvent: 'wat',
595+
preventDefault: 'wat',
596+
stopPropagation: 'wat',
597+
},
598+
baz: NaN,
599+
qux: function qux(): void {
600+
/*no-empty*/
601+
},
602+
};
603+
const result = safeNormalize(obj);
604+
expect(result).toEqual({
605+
foo: '[SyntheticEvent]',
606+
baz: '[NaN]',
607+
qux: '[Function: qux]',
608+
});
609+
});
590610
});

0 commit comments

Comments
 (0)