Skip to content

Commit

Permalink
events: refactor to use primordials in lib/events
Browse files Browse the repository at this point in the history
Replace code that's vulnerable to Prototype Pollution with Primordials.
  • Loading branch information
marsonya committed Apr 6, 2021
1 parent 8b05e32 commit f93bcf8
Showing 1 changed file with 27 additions and 18 deletions.
45 changes: 27 additions & 18 deletions lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,17 @@

const {
ArrayPrototypeForEach,
ArrayPrototypeIndexOf,
ArrayPrototypeJoin,
ArrayPrototypePush,
ArrayPrototypeShift,
ArrayPrototypeSlice,
ArrayPrototypeSplice,
ArrayPrototypeUnshift,
Boolean,
Error,
ErrorCaptureStackTrace,
FunctionPrototypeBind,
FunctionPrototypeCall,
MathMin,
NumberIsNaN,
Expand All @@ -42,9 +48,10 @@ const {
ReflectApply,
ReflectOwnKeys,
String,
StringPrototypeSplit,
Symbol,
SymbolFor,
SymbolAsyncIterator
SymbolAsyncIterator,
} = primordials;
const kRejection = SymbolFor('nodejs.rejection');

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

const errStack = err.stack.split('\n').slice(1);
const ownStack = own.stack.split('\n').slice(1);
const errStack = ArrayPrototypeSlice(
StringPrototypeSplit(err.stack, '\n'), 1);
const ownStack = ArrayPrototypeSlice(
StringPrototypeSplit(own.stack, '\n'), 1);

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

return err.stack + sep + ownStack.join('\n');
return err.stack + sep + ArrayPrototypeJoin(ownStack, '\n');
}

EventEmitter.prototype.emit = function emit(type, ...args) {
Expand All @@ -336,7 +345,7 @@ EventEmitter.prototype.emit = function emit(type, ...args) {
const capture = {};
ErrorCaptureStackTrace(capture, EventEmitter.prototype.emit);
ObjectDefineProperty(er, kEnhanceStackBeforeInspector, {
value: enhanceStackTrace.bind(this, er, capture),
value: FunctionPrototypeBind(enhanceStackTrace, this, er, capture),
configurable: true
});
} catch {}
Expand Down Expand Up @@ -430,9 +439,9 @@ function _addListener(target, type, listener, prepend) {
prepend ? [listener, existing] : [existing, listener];
// If we've already got an array, just append.
} else if (prepend) {
existing.unshift(listener);
ArrayPrototypeUnshift(existing, listener);
} else {
existing.push(listener);
ArrayPrototypePush(existing, listener);
}

// Check for listener leak
Expand Down Expand Up @@ -472,14 +481,14 @@ function onceWrapper() {
this.target.removeListener(this.type, this.wrapFn);
this.fired = true;
if (arguments.length === 0)
return this.listener.call(this.target);
return this.listener.apply(this.target, arguments);
return FunctionPrototypeCall(this.listener, this.target);
return ReflectApply(this.listener, this.target, arguments);
}
}

function _onceWrap(target, type, listener) {
const state = { fired: false, wrapFn: undefined, target, type, listener };
const wrapped = onceWrapper.bind(state);
const wrapped = FunctionPrototypeBind(onceWrapper, state);
wrapped.listener = listener;
state.wrapFn = wrapped;
return wrapped;
Expand Down Expand Up @@ -535,7 +544,7 @@ EventEmitter.prototype.removeListener =
return this;

if (position === 0)
list.shift();
ArrayPrototypeShift(list);
else {
if (spliceOne === undefined)
spliceOne = require('internal/util').spliceOne;
Expand Down Expand Up @@ -629,7 +638,7 @@ EventEmitter.listenerCount = function(emitter, type) {
if (typeof emitter.listenerCount === 'function') {
return emitter.listenerCount(type);
}
return listenerCount.call(emitter, type);
return FunctionPrototypeCall(listenerCount, emitter, type);
};

EventEmitter.prototype.listenerCount = listenerCount;
Expand Down Expand Up @@ -785,7 +794,7 @@ function on(emitter, event, options) {
const iterator = ObjectSetPrototypeOf({
next() {
// First, we consume all unread events
const value = unconsumedEvents.shift();
const value = ArrayPrototypeShift(unconsumedEvents);
if (value) {
return PromiseResolve(createIterResult(value, false));
}
Expand Down Expand Up @@ -867,7 +876,7 @@ function on(emitter, event, options) {
}

function eventHandler(...args) {
const promise = unconsumedPromises.shift();
const promise = ArrayPrototypeShift(unconsumedPromises);
if (promise) {
promise.resolve(createIterResult(args, false));
} else {
Expand All @@ -878,7 +887,7 @@ function on(emitter, event, options) {
function errorHandler(err) {
finished = true;

const toError = unconsumedPromises.shift();
const toError = ArrayPrototypeShift(unconsumedPromises);

if (toError) {
toError.reject(err);
Expand Down

0 comments on commit f93bcf8

Please sign in to comment.