Skip to content

Commit f93bcf8

Browse files
committed
events: refactor to use primordials in lib/events
Replace code that's vulnerable to Prototype Pollution with Primordials.
1 parent 8b05e32 commit f93bcf8

File tree

1 file changed

+27
-18
lines changed

1 file changed

+27
-18
lines changed

lib/events.js

+27-18
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,17 @@
2323

2424
const {
2525
ArrayPrototypeForEach,
26+
ArrayPrototypeIndexOf,
27+
ArrayPrototypeJoin,
2628
ArrayPrototypePush,
29+
ArrayPrototypeShift,
2730
ArrayPrototypeSlice,
31+
ArrayPrototypeSplice,
32+
ArrayPrototypeUnshift,
2833
Boolean,
2934
Error,
3035
ErrorCaptureStackTrace,
36+
FunctionPrototypeBind,
3137
FunctionPrototypeCall,
3238
MathMin,
3339
NumberIsNaN,
@@ -42,9 +48,10 @@ const {
4248
ReflectApply,
4349
ReflectOwnKeys,
4450
String,
51+
StringPrototypeSplit,
4552
Symbol,
4653
SymbolFor,
47-
SymbolAsyncIterator
54+
SymbolAsyncIterator,
4855
} = primordials;
4956
const kRejection = SymbolFor('nodejs.rejection');
5057

@@ -274,7 +281,7 @@ EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
274281
function identicalSequenceRange(a, b) {
275282
for (let i = 0; i < a.length - 3; i++) {
276283
// Find the first entry of b that matches the current entry of a.
277-
const pos = b.indexOf(a[i]);
284+
const pos = ArrayPrototypeIndexOf(b, a[i]);
278285
if (pos !== -1) {
279286
const rest = b.length - pos;
280287
if (rest > 3) {
@@ -303,16 +310,18 @@ function enhanceStackTrace(err, own) {
303310
} catch {}
304311
const sep = `\nEmitted 'error' event${ctorInfo} at:\n`;
305312

306-
const errStack = err.stack.split('\n').slice(1);
307-
const ownStack = own.stack.split('\n').slice(1);
313+
const errStack = ArrayPrototypeSlice(
314+
StringPrototypeSplit(err.stack, '\n'), 1);
315+
const ownStack = ArrayPrototypeSlice(
316+
StringPrototypeSplit(own.stack, '\n'), 1);
308317

309318
const { 0: len, 1: off } = identicalSequenceRange(ownStack, errStack);
310319
if (len > 0) {
311-
ownStack.splice(off + 1, len - 2,
312-
' [... lines matching original stack trace ...]');
320+
ArrayPrototypeSplice(ownStack, off + 1, len - 2,
321+
' [... lines matching original stack trace ...]');
313322
}
314323

315-
return err.stack + sep + ownStack.join('\n');
324+
return err.stack + sep + ArrayPrototypeJoin(ownStack, '\n');
316325
}
317326

318327
EventEmitter.prototype.emit = function emit(type, ...args) {
@@ -336,7 +345,7 @@ EventEmitter.prototype.emit = function emit(type, ...args) {
336345
const capture = {};
337346
ErrorCaptureStackTrace(capture, EventEmitter.prototype.emit);
338347
ObjectDefineProperty(er, kEnhanceStackBeforeInspector, {
339-
value: enhanceStackTrace.bind(this, er, capture),
348+
value: FunctionPrototypeBind(enhanceStackTrace, this, er, capture),
340349
configurable: true
341350
});
342351
} catch {}
@@ -430,9 +439,9 @@ function _addListener(target, type, listener, prepend) {
430439
prepend ? [listener, existing] : [existing, listener];
431440
// If we've already got an array, just append.
432441
} else if (prepend) {
433-
existing.unshift(listener);
442+
ArrayPrototypeUnshift(existing, listener);
434443
} else {
435-
existing.push(listener);
444+
ArrayPrototypePush(existing, listener);
436445
}
437446

438447
// Check for listener leak
@@ -472,14 +481,14 @@ function onceWrapper() {
472481
this.target.removeListener(this.type, this.wrapFn);
473482
this.fired = true;
474483
if (arguments.length === 0)
475-
return this.listener.call(this.target);
476-
return this.listener.apply(this.target, arguments);
484+
return FunctionPrototypeCall(this.listener, this.target);
485+
return ReflectApply(this.listener, this.target, arguments);
477486
}
478487
}
479488

480489
function _onceWrap(target, type, listener) {
481490
const state = { fired: false, wrapFn: undefined, target, type, listener };
482-
const wrapped = onceWrapper.bind(state);
491+
const wrapped = FunctionPrototypeBind(onceWrapper, state);
483492
wrapped.listener = listener;
484493
state.wrapFn = wrapped;
485494
return wrapped;
@@ -535,7 +544,7 @@ EventEmitter.prototype.removeListener =
535544
return this;
536545

537546
if (position === 0)
538-
list.shift();
547+
ArrayPrototypeShift(list);
539548
else {
540549
if (spliceOne === undefined)
541550
spliceOne = require('internal/util').spliceOne;
@@ -629,7 +638,7 @@ EventEmitter.listenerCount = function(emitter, type) {
629638
if (typeof emitter.listenerCount === 'function') {
630639
return emitter.listenerCount(type);
631640
}
632-
return listenerCount.call(emitter, type);
641+
return FunctionPrototypeCall(listenerCount, emitter, type);
633642
};
634643

635644
EventEmitter.prototype.listenerCount = listenerCount;
@@ -785,7 +794,7 @@ function on(emitter, event, options) {
785794
const iterator = ObjectSetPrototypeOf({
786795
next() {
787796
// First, we consume all unread events
788-
const value = unconsumedEvents.shift();
797+
const value = ArrayPrototypeShift(unconsumedEvents);
789798
if (value) {
790799
return PromiseResolve(createIterResult(value, false));
791800
}
@@ -867,7 +876,7 @@ function on(emitter, event, options) {
867876
}
868877

869878
function eventHandler(...args) {
870-
const promise = unconsumedPromises.shift();
879+
const promise = ArrayPrototypeShift(unconsumedPromises);
871880
if (promise) {
872881
promise.resolve(createIterResult(args, false));
873882
} else {
@@ -878,7 +887,7 @@ function on(emitter, event, options) {
878887
function errorHandler(err) {
879888
finished = true;
880889

881-
const toError = unconsumedPromises.shift();
890+
const toError = ArrayPrototypeShift(unconsumedPromises);
882891

883892
if (toError) {
884893
toError.reject(err);

0 commit comments

Comments
 (0)