events: make abort_controller event trusted

The AbortController abort event is trusted, currently we fire all
events with isTrusted: false. Allow dispatching events
internally with `isTrusted: true` and add a test for it.

Co-Authored-By: ExE Boss <3889017+ExE-Boss@users.noreply.github.com>
Fixes: https://github.com/nodejs/node/issues/35748

PR-URL: https://github.com/nodejs/node/pull/35811
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Benjamin Gruenbaum 2020-10-26 13:56:48 +02:00 committed by Node.js GitHub Bot
parent 81ba3ae699
commit f20a783a31
5 changed files with 59 additions and 6 deletions

View File

@ -1282,9 +1282,10 @@ This is not used in Node.js and is provided purely for completeness.
added: v14.5.0
-->
* Type: {boolean} Always returns `false`.
* Type: {boolean} True for Node.js internal events, false otherwise.
This is not used in Node.js and is provided purely for completeness.
Currently only `AbortSignal`s' `"abort"` event is fired with `isTrusted`
set to `true`.
#### `event.preventDefault()`
<!-- YAML

View File

@ -11,7 +11,8 @@ const {
const {
EventTarget,
Event
Event,
kTrustEvent
} = require('internal/event_target');
const {
customInspectSymbol,
@ -49,7 +50,9 @@ ObjectDefineProperties(AbortSignal.prototype, {
function abortSignal(signal) {
if (signal[kAborted]) return;
signal[kAborted] = true;
const event = new Event('abort');
const event = new Event('abort', {
[kTrustEvent]: true
});
if (typeof signal.onabort === 'function') {
signal.onabort(event);
}

View File

@ -9,10 +9,12 @@ const {
ObjectAssign,
ObjectDefineProperties,
ObjectDefineProperty,
ObjectGetOwnPropertyDescriptor,
String,
Symbol,
SymbolFor,
SymbolToStringTag,
SafeWeakSet,
} = primordials;
const {
@ -41,6 +43,7 @@ const kRemoveListener = Symbol('kRemoveListener');
const kIsNodeStyleListener = Symbol('kIsNodeStyleListener');
const kMaxListeners = Symbol('kMaxListeners');
const kMaxListenersWarned = Symbol('kMaxListenersWarned');
const kTrustEvent = Symbol('kTrustEvent');
// Lazy load perf_hooks to avoid the additional overhead on startup
let perf_hooks;
@ -61,7 +64,12 @@ const kBubbles = Symbol('bubbles');
const kComposed = Symbol('composed');
const kPropagationStopped = Symbol('propagationStopped');
const isTrusted = () => false;
const isTrustedSet = new SafeWeakSet();
const isTrusted = ObjectGetOwnPropertyDescriptor({
get isTrusted() {
return isTrustedSet.has(this);
}
}, 'isTrusted').get;
class Event {
constructor(type, options) {
@ -77,6 +85,10 @@ class Event {
this[kDefaultPrevented] = false;
this[kTimestamp] = lazyNow();
this[kPropagationStopped] = false;
if (options != null && options[kTrustEvent]) {
isTrustedSet.add(this);
}
// isTrusted is special (LegacyUnforgeable)
ObjectDefineProperty(this, 'isTrusted', {
get: isTrusted,
@ -573,5 +585,6 @@ module.exports = {
initNodeEventTarget,
kCreateEvent,
kNewListener,
kTrustEvent,
kRemoveListener,
};

View File

@ -101,6 +101,10 @@ primordials.SafeSet = makeSafe(
Set,
class SafeSet extends Set {}
);
primordials.SafeWeakSet = makeSafe(
WeakSet,
class SafeWeakSet extends WeakSet {}
);
primordials.SafePromise = makeSafe(
Promise,
class SafePromise extends Promise {}

View File

@ -1,11 +1,13 @@
// Flags: --no-warnings
// Flags: --no-warnings --expose-internals
'use strict';
const common = require('../common');
const { ok, strictEqual } = require('assert');
const { Event } = require('internal/event_target');
{
// Tests that abort is fired with the correct event type on AbortControllers
const ac = new AbortController();
ok(ac.signal);
ac.signal.onabort = common.mustCall((event) => {
@ -20,3 +22,33 @@ const { ok, strictEqual } = require('assert');
ac.abort();
ok(ac.signal.aborted);
}
{
// Tests that abort events are trusted
const ac = new AbortController();
ac.signal.addEventListener('abort', common.mustCall((event) => {
ok(event.isTrusted);
}));
ac.abort();
}
{
// Tests that abort events have the same `isTrusted` reference
const first = new AbortController();
const second = new AbortController();
let ev1, ev2;
const ev3 = new Event('abort');
first.signal.addEventListener('abort', common.mustCall((event) => {
ev1 = event;
}));
second.signal.addEventListener('abort', common.mustCall((event) => {
ev2 = event;
}));
first.abort();
second.abort();
const firstTrusted = Reflect.getOwnPropertyDescriptor(ev1, 'isTrusted').get;
const secondTrusted = Reflect.getOwnPropertyDescriptor(ev2, 'isTrusted').get;
const untrusted = Reflect.getOwnPropertyDescriptor(ev3, 'isTrusted').get;
strictEqual(firstTrusted, secondTrusted);
strictEqual(untrusted, firstTrusted);
}