Skip to content

Commit f529f73

Browse files
committed
lib: brand check event handler property receivers
Event handler properties defined by `defineEventHandler` should check if the receiver is a valid `EventTarget`. PR-URL: #44483 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Minwoo Jung <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent ecd5de0 commit f529f73

File tree

2 files changed

+47
-27
lines changed

2 files changed

+47
-27
lines changed

lib/internal/event_target.js

+39-26
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const {
3434
ERR_INVALID_THIS,
3535
}
3636
} = require('internal/errors');
37-
const { validateObject, validateString } = require('internal/validators');
37+
const { validateObject, validateString, validateInternalField } = require('internal/validators');
3838

3939
const {
4040
customInspectSymbol,
@@ -492,6 +492,7 @@ function initEventTarget(self) {
492492
self[kEvents] = new SafeMap();
493493
self[kMaxEventTargetListeners] = EventEmitter.defaultMaxListeners;
494494
self[kMaxEventTargetListenersWarned] = false;
495+
self[kHandlers] = new SafeMap();
495496
}
496497

497498
class EventTarget {
@@ -1021,34 +1022,46 @@ function makeEventHandler(handler) {
10211022

10221023
function defineEventHandler(emitter, name) {
10231024
// 8.1.5.1 Event handlers - basically `on[eventName]` attributes
1024-
ObjectDefineProperty(emitter, `on${name}`, {
1025+
const propName = `on${name}`;
1026+
function get() {
1027+
validateInternalField(this, kHandlers, 'EventTarget');
1028+
return this[kHandlers]?.get(name)?.handler ?? null;
1029+
}
1030+
ObjectDefineProperty(get, 'name', {
10251031
__proto__: null,
1026-
get() {
1027-
return this[kHandlers]?.get(name)?.handler ?? null;
1028-
},
1029-
set(value) {
1030-
if (!this[kHandlers]) {
1031-
this[kHandlers] = new SafeMap();
1032+
value: `get ${propName}`,
1033+
});
1034+
1035+
function set(value) {
1036+
validateInternalField(this, kHandlers, 'EventTarget');
1037+
let wrappedHandler = this[kHandlers]?.get(name);
1038+
if (wrappedHandler) {
1039+
if (typeof wrappedHandler.handler === 'function') {
1040+
this[kEvents].get(name).size--;
1041+
const size = this[kEvents].get(name).size;
1042+
this[kRemoveListener](size, name, wrappedHandler.handler, false);
10321043
}
1033-
let wrappedHandler = this[kHandlers]?.get(name);
1034-
if (wrappedHandler) {
1035-
if (typeof wrappedHandler.handler === 'function') {
1036-
this[kEvents].get(name).size--;
1037-
const size = this[kEvents].get(name).size;
1038-
this[kRemoveListener](size, name, wrappedHandler.handler, false);
1039-
}
1040-
wrappedHandler.handler = value;
1041-
if (typeof wrappedHandler.handler === 'function') {
1042-
this[kEvents].get(name).size++;
1043-
const size = this[kEvents].get(name).size;
1044-
this[kNewListener](size, name, value, false, false, false, false);
1045-
}
1046-
} else {
1047-
wrappedHandler = makeEventHandler(value);
1048-
this.addEventListener(name, wrappedHandler);
1044+
wrappedHandler.handler = value;
1045+
if (typeof wrappedHandler.handler === 'function') {
1046+
this[kEvents].get(name).size++;
1047+
const size = this[kEvents].get(name).size;
1048+
this[kNewListener](size, name, value, false, false, false, false);
10491049
}
1050-
this[kHandlers].set(name, wrappedHandler);
1051-
},
1050+
} else {
1051+
wrappedHandler = makeEventHandler(value);
1052+
this.addEventListener(name, wrappedHandler);
1053+
}
1054+
this[kHandlers].set(name, wrappedHandler);
1055+
}
1056+
ObjectDefineProperty(set, 'name', {
1057+
__proto__: null,
1058+
value: `set ${propName}`,
1059+
});
1060+
1061+
ObjectDefineProperty(emitter, propName, {
1062+
__proto__: null,
1063+
get,
1064+
set,
10521065
configurable: true,
10531066
enumerable: true
10541067
});

lib/internal/validators.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,12 @@ function validateLinkHeaderValue(value, name) {
418418
}
419419
}
420420

421+
const validateInternalField = hideStackFrames((object, fieldKey, className) => {
422+
if (typeof object !== 'object' || object === null || !ObjectPrototypeHasOwnProperty(object, fieldKey)) {
423+
throw new ERR_INVALID_ARG_TYPE('this', className, object);
424+
}
425+
});
426+
421427
module.exports = {
422428
isInt32,
423429
isUint32,
@@ -440,5 +446,6 @@ module.exports = {
440446
validateUndefined,
441447
validateUnion,
442448
validateAbortSignal,
443-
validateLinkHeaderValue
449+
validateLinkHeaderValue,
450+
validateInternalField,
444451
};

0 commit comments

Comments
 (0)