From e0f5be240e599fb51cd11554037d939e3185dbf2 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Fri, 28 Sep 2018 11:51:21 +0200 Subject: [PATCH] lib: hide lots of internal properties The symbol properties will all show up when inspecting the object that contains the enumerable symbols. Therefore, it's best to hide them from the user. That way the user concentrates on the actual important information and is not confronted with information that is not necessary for them. --- lib/_http_server.js | 16 +++++- lib/async_hooks.js | 15 ++++-- lib/inspector.js | 14 +++-- lib/internal/console/constructor.js | 67 +++++++++++------------- lib/internal/crypto/hash.js | 33 +++++++----- lib/internal/encoding.js | 26 ++++++--- lib/internal/fs/promises.js | 7 ++- lib/internal/fs/utils.js | 14 ++++- lib/internal/fs/watchers.js | 16 +++++- lib/internal/trace_events_async_hooks.js | 7 ++- lib/internal/url.js | 6 +++ lib/readline.js | 17 +++++- lib/repl.js | 10 +++- lib/string_decoder.js | 7 ++- lib/trace_events.js | 13 +++-- 15 files changed, 190 insertions(+), 78 deletions(-) diff --git a/lib/_http_server.js b/lib/_http_server.js index c171b1d3e78a..291fa614ab0e 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -286,8 +286,20 @@ function Server(options, requestListener) { throw new ERR_INVALID_ARG_TYPE('options', 'object', options); } - this[kIncomingMessage] = options.IncomingMessage || IncomingMessage; - this[kServerResponse] = options.ServerResponse || ServerResponse; + Object.defineProperties(this, { + [kIncomingMessage]: { + value: options.IncomingMessage || IncomingMessage, + configurable: true, + writable: true, + enumerable: false + }, + [kServerResponse]: { + value: options.ServerResponse || ServerResponse, + configurable: true, + writable: true, + enumerable: false + }, + }); net.Server.call(this, { allowHalfOpen: true }); diff --git a/lib/async_hooks.js b/lib/async_hooks.js index 7d160707415a..f56df084814e 100644 --- a/lib/async_hooks.js +++ b/lib/async_hooks.js @@ -155,10 +155,17 @@ class AsyncResource { throw new ERR_INVALID_ASYNC_ID('triggerAsyncId', triggerAsyncId); } - this[async_id_symbol] = newAsyncId(); - this[trigger_async_id_symbol] = triggerAsyncId; - // this prop name (destroyed) has to be synchronized with C++ - this[destroyedSymbol] = { destroyed: false }; + const attributes = { + configurable: true, + writable: true, + enumerable: false + }; + Object.defineProperties(this, { + [async_id_symbol]: { ...attributes, value: newAsyncId() }, + [trigger_async_id_symbol]: { ...attributes, value: triggerAsyncId }, + // This prop name (destroyed) has to be synchronized with C++ + [destroyedSymbol]: { ...attributes, value: { destroyed: false } } + }); emitInit( this[async_id_symbol], type, this[trigger_async_id_symbol], this diff --git a/lib/inspector.js b/lib/inspector.js index 14ea01e6adc6..16a5713ed541 100644 --- a/lib/inspector.js +++ b/lib/inspector.js @@ -24,9 +24,17 @@ const onMessageSymbol = Symbol('onMessage'); class Session extends EventEmitter { constructor() { super(); - this[connectionSymbol] = null; - this[nextIdSymbol] = 1; - this[messageCallbacksSymbol] = new Map(); + + const attributes = { + configurable: true, + writable: true, + enumerable: false + }; + Object.defineProperties(this, { + [connectionSymbol]: { ...attributes, value: null }, + [nextIdSymbol]: { ...attributes, value: 1 }, + [messageCallbacksSymbol]: { ...attributes, value: new Map() } + }); } connect() { diff --git a/lib/internal/console/constructor.js b/lib/internal/console/constructor.js index f607bf4648bb..6c58132cfc5f 100644 --- a/lib/internal/console/constructor.js +++ b/lib/internal/console/constructor.js @@ -42,12 +42,8 @@ let cliTable; // Track amount of indentation required via `console.group()`. const kGroupIndent = Symbol('kGroupIndent'); -const kFormatForStderr = Symbol('kFormatForStderr'); -const kFormatForStdout = Symbol('kFormatForStdout'); -const kGetInspectOptions = Symbol('kGetInspectOptions'); const kColorMode = Symbol('kColorMode'); const kIsConsole = Symbol('kIsConsole'); -const kWriteToConsole = Symbol('kWriteToConsole'); const kBindProperties = Symbol('kBindProperties'); const kBindStreamsEager = Symbol('kBindStreamsEager'); const kBindStreamsLazy = Symbol('kBindStreamsLazy'); @@ -163,15 +159,14 @@ Console.prototype[kBindProperties] = function(ignoreErrors, colorMode) { ...consolePropAttributes, value: Boolean(ignoreErrors) }, - '_times': { ...consolePropAttributes, value: new Map() } + '_times': { ...consolePropAttributes, value: new Map() }, + // TODO(joyeecheung): use consolePropAttributes for these + // Corresponds to https://console.spec.whatwg.org/#count-map + [kCounts]: { ...consolePropAttributes, value: new Map() }, + [kColorMode]: { ...consolePropAttributes, value: colorMode }, + [kIsConsole]: { ...consolePropAttributes, value: true }, + [kGroupIndent]: { ...consolePropAttributes, value: '' }, }); - - // TODO(joyeecheung): use consolePropAttributes for these - // Corresponds to https://console.spec.whatwg.org/#count-map - this[kCounts] = new Map(); - this[kColorMode] = colorMode; - this[kIsConsole] = true; - this[kGroupIndent] = ''; }; // Make a function that can serve as the callback passed to `stream.write()`. @@ -195,14 +190,14 @@ function createWriteErrorHandler(instance, streamSymbol) { }; } -Console.prototype[kWriteToConsole] = function(streamSymbol, string) { - const ignoreErrors = this._ignoreErrors; - const groupIndent = this[kGroupIndent]; +function writeToConsole(self, streamSymbol, string) { + const ignoreErrors = self._ignoreErrors; + const groupIndent = self[kGroupIndent]; const useStdout = streamSymbol === kUseStdout; - const stream = useStdout ? this._stdout : this._stderr; + const stream = useStdout ? self._stdout : self._stderr; const errorHandler = useStdout ? - this._stdoutErrorHandler : this._stderrErrorHandler; + self._stdoutErrorHandler : self._stderrErrorHandler; if (groupIndent.length !== 0) { if (string.indexOf('\n') !== -1) { @@ -231,12 +226,13 @@ Console.prototype[kWriteToConsole] = function(streamSymbol, string) { } finally { stream.removeListener('error', noop); } -}; +} const kColorInspectOptions = { colors: true }; const kNoColorInspectOptions = {}; -Console.prototype[kGetInspectOptions] = function(stream) { - let color = this[kColorMode]; + +function getInspectOptions(self, stream) { + let color = self[kColorMode]; if (color === 'auto') { color = stream.isTTY && ( typeof stream.getColorDepth === 'function' ? @@ -244,20 +240,15 @@ Console.prototype[kGetInspectOptions] = function(stream) { } return color ? kColorInspectOptions : kNoColorInspectOptions; -}; - -Console.prototype[kFormatForStdout] = function(args) { - const opts = this[kGetInspectOptions](this._stdout); - return util.formatWithOptions(opts, ...args); -}; +} -Console.prototype[kFormatForStderr] = function(args) { - const opts = this[kGetInspectOptions](this._stderr); +function format(self, prop, args) { + const opts = getInspectOptions(self, self[prop]); return util.formatWithOptions(opts, ...args); -}; +} Console.prototype.log = function log(...args) { - this[kWriteToConsole](kUseStdout, this[kFormatForStdout](args)); + writeToConsole(this, kUseStdout, format(this, '_stdout', args)); }; Console.prototype.debug = Console.prototype.log; @@ -265,16 +256,18 @@ Console.prototype.info = Console.prototype.log; Console.prototype.dirxml = Console.prototype.log; Console.prototype.warn = function warn(...args) { - this[kWriteToConsole](kUseStderr, this[kFormatForStderr](args)); + writeToConsole(this, kUseStderr, format(this, '_stderr', args)); }; Console.prototype.error = Console.prototype.warn; Console.prototype.dir = function dir(object, options) { - options = Object.assign({ - customInspect: false - }, this[kGetInspectOptions](this._stdout), options); - this[kWriteToConsole](kUseStdout, util.inspect(object, options)); + options = { + customInspect: false, + ...getInspectOptions(this, this._stdout), + ...options + }; + writeToConsole(this, kUseStdout, util.inspect(object, options)); }; Console.prototype.time = function time(label = 'default') { @@ -325,7 +318,7 @@ function timeLogImpl(self, name, label, data) { Console.prototype.trace = function trace(...args) { const err = { name: 'Trace', - message: this[kFormatForStderr](args) + message: format(this, '_stderr', args) }; Error.captureStackTrace(err, trace); this.error(err.stack); @@ -414,7 +407,7 @@ Console.prototype.table = function(tabularData, properties) { if (v !== null && typeof v === 'object' && !isArray(v) && ObjectKeys(v).length > 2) opt.depth = -1; - Object.assign(opt, this[kGetInspectOptions](this._stdout)); + Object.assign(opt, getInspectOptions(this, this._stdout)); return util.inspect(v, opt); }; const getIndexArray = (length) => ArrayFrom({ length }, (_, i) => inspect(i)); diff --git a/lib/internal/crypto/hash.js b/lib/internal/crypto/hash.js index 6803d8fa954e..3187edeaab9e 100644 --- a/lib/internal/crypto/hash.js +++ b/lib/internal/crypto/hash.js @@ -26,16 +26,20 @@ const { normalizeEncoding } = require('internal/util'); const { isArrayBufferView } = require('internal/util/types'); const LazyTransform = require('internal/streams/lazy_transform'); const kState = Symbol('kState'); -const kFinalized = Symbol('kFinalized'); function Hash(algorithm, options) { if (!(this instanceof Hash)) return new Hash(algorithm, options); validateString(algorithm, 'algorithm'); this[kHandle] = new _Hash(algorithm); - this[kState] = { - [kFinalized]: false - }; + Object.defineProperty(this, kState, { + value: { + finalized: false + }, + configurable: true, + writable: true, + enumerable: false + }); LazyTransform.call(this, options); } @@ -53,7 +57,7 @@ Hash.prototype._flush = function _flush(callback) { Hash.prototype.update = function update(data, encoding) { const state = this[kState]; - if (state[kFinalized]) + if (state.finalized) throw new ERR_CRYPTO_HASH_FINALIZED(); if (typeof data !== 'string' && !isArrayBufferView(data)) { @@ -69,7 +73,7 @@ Hash.prototype.update = function update(data, encoding) { Hash.prototype.digest = function digest(outputEncoding) { const state = this[kState]; - if (state[kFinalized]) + if (state.finalized) throw new ERR_CRYPTO_HASH_FINALIZED(); outputEncoding = outputEncoding || getDefaultEncoding(); if (normalizeEncoding(outputEncoding) === 'utf16le') @@ -77,7 +81,7 @@ Hash.prototype.digest = function digest(outputEncoding) { // Explicit conversion for backward compatibility. const ret = this[kHandle].digest(`${outputEncoding}`); - state[kFinalized] = true; + state.finalized = true; return ret; }; @@ -94,9 +98,14 @@ function Hmac(hmac, key, options) { } this[kHandle] = new _Hmac(); this[kHandle].init(hmac, toBuf(key)); - this[kState] = { - [kFinalized]: false - }; + Object.defineProperty(this, kState, { + value: { + finalized: false + }, + configurable: true, + writable: true, + enumerable: false + }); LazyTransform.call(this, options); } @@ -110,14 +119,14 @@ Hmac.prototype.digest = function digest(outputEncoding) { if (normalizeEncoding(outputEncoding) === 'utf16le') throw new ERR_CRYPTO_HASH_DIGEST_NO_UTF16(); - if (state[kFinalized]) { + if (state.finalized) { const buf = Buffer.from(''); return outputEncoding === 'buffer' ? buf : buf.toString(outputEncoding); } // Explicit conversion for backward compatibility. const ret = this[kHandle].digest(`${outputEncoding}`); - state[kFinalized] = true; + state.finalized = true; return ret; }; diff --git a/lib/internal/encoding.js b/lib/internal/encoding.js index ce3cc7411a65..4a6ba1dcb180 100644 --- a/lib/internal/encoding.js +++ b/lib/internal/encoding.js @@ -305,7 +305,12 @@ function getEncodingFromLabel(label) { class TextEncoder { constructor() { - this[kEncoder] = true; + Object.defineProperty(this, kEncoder, { + value: true, + configurable: true, + writable: true, + enumerable: false + }); } get encoding() { @@ -437,12 +442,19 @@ function makeTextDecoderJS() { flags |= options.ignoreBOM ? CONVERTER_FLAGS_IGNORE_BOM : 0; } - this[kDecoder] = true; - // StringDecoder will normalize WHATWG encoding to Node.js encoding. - this[kHandle] = new (lazyStringDecoder())(enc); - this[kFlags] = flags; - this[kEncoding] = enc; - this[kBOMSeen] = false; + const attributes = { + configurable: true, + writable: true, + enumerable: false + }; + Object.defineProperties(this, { + [kDecoder]: { ...attributes, value: true }, + // StringDecoder will normalize WHATWG encoding to Node.js encoding. + [kHandle]: { ...attributes, value: new (lazyStringDecoder())(enc) }, + [kFlags]: { ...attributes, value: flags }, + [kEncoding]: { ...attributes, value: enc }, + [kBOMSeen]: { ...attributes, value: false } + }); } decode(input = empty, options = {}) { diff --git a/lib/internal/fs/promises.js b/lib/internal/fs/promises.js index 33c510ed5ca7..80f3ecb026dc 100644 --- a/lib/internal/fs/promises.js +++ b/lib/internal/fs/promises.js @@ -47,7 +47,12 @@ const getDirectoryEntriesPromise = promisify(getDirents); class FileHandle { constructor(filehandle) { - this[kHandle] = filehandle; + Object.defineProperty(this, kHandle, { + value: filehandle, + configurable: true, + writable: true, + enumerable: false + }); } getAsyncId() { diff --git a/lib/internal/fs/utils.js b/lib/internal/fs/utils.js index 0df13354acc6..09f3608b0e34 100644 --- a/lib/internal/fs/utils.js +++ b/lib/internal/fs/utils.js @@ -64,7 +64,12 @@ function assertEncoding(encoding) { class Dirent { constructor(name, type) { this.name = name; - this[kType] = type; + Object.defineProperty(this, kType, { + value: type, + configurable: true, + writable: true, + enumerable: false + }); } isDirectory() { @@ -99,7 +104,12 @@ class Dirent { class DirentFromStats extends Dirent { constructor(name, stats) { super(name, null); - this[kStats] = stats; + Object.defineProperty(this, kStats, { + value: stats, + configurable: true, + writable: true, + enumerable: false + }); } } diff --git a/lib/internal/fs/watchers.js b/lib/internal/fs/watchers.js index e026aa8192c3..c8a7a599ff1c 100644 --- a/lib/internal/fs/watchers.js +++ b/lib/internal/fs/watchers.js @@ -33,8 +33,20 @@ function StatWatcher(bigint) { EventEmitter.call(this); this._handle = null; - this[kOldStatus] = -1; - this[kUseBigint] = bigint; + Object.defineProperties(this, { + [kOldStatus]: { + value: -1, + configurable: true, + writable: true, + enumerable: false + }, + [kUseBigint]: { + value: bigint, + configurable: true, + writable: true, + enumerable: false + } + }); } util.inherits(StatWatcher, EventEmitter); diff --git a/lib/internal/trace_events_async_hooks.js b/lib/internal/trace_events_async_hooks.js index 0cf5d517c2bf..61c598e178be 100644 --- a/lib/internal/trace_events_async_hooks.js +++ b/lib/internal/trace_events_async_hooks.js @@ -69,7 +69,12 @@ function createHook() { enable() { if (this[kEnabled]) return; - this[kEnabled] = true; + Object.defineProperty(this, kEnabled, { + value: true, + configurable: true, + writable: true, + enumerable: false + }); hook.enable(); }, diff --git a/lib/internal/url.js b/lib/internal/url.js index 440fc0315ed3..67507d39908a 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -122,6 +122,12 @@ class URLSearchParams { // Default parameter is necessary to keep URLSearchParams.length === 0 in // accordance with Web IDL spec. constructor(init = undefined) { + // Define the property upfront. Afterwards it the descriptor stays the same. + Object.defineProperty(this, searchParams, { + value: undefined, + configurable: true, + writable: true + }); if (init === null || init === undefined) { this[searchParams] = []; } else if (typeof init === 'object' || typeof init === 'function') { diff --git a/lib/readline.js b/lib/readline.js index 049f5aaeccf4..2507fa44d8ad 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -1071,9 +1071,22 @@ function emitKeypressEvents(stream, iface) { if (StringDecoder === undefined) StringDecoder = require('string_decoder').StringDecoder; - stream[KEYPRESS_DECODER] = new StringDecoder('utf8'); - stream[ESCAPE_DECODER] = emitKeys(stream); + Object.defineProperties(stream, { + [KEYPRESS_DECODER]: { + value: new StringDecoder('utf8'), + configurable: true, + writable: true, + enumerable: false + }, + [ESCAPE_DECODER]: { + value: emitKeys(stream), + configurable: true, + writable: true, + enumerable: false + } + }); + stream[ESCAPE_DECODER].next(); const escapeCodeTimeout = () => stream[ESCAPE_DECODER].next(''); diff --git a/lib/repl.js b/lib/repl.js index 5dbd02fd231c..9395ed248b74 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -187,7 +187,12 @@ function REPLServer(prompt, self.breakEvalOnSigint = !!breakEvalOnSigint; self.editorMode = false; // Context id for use with the inspector protocol. - self[kContextId] = undefined; + Object.defineProperty(self, kContextId, { + value: undefined, + configurable: true, + writable: true, + enumerable: false + }); // Just for backwards compat, see github.com/joyent/node/pull/7127 self.rli = this; @@ -816,6 +821,7 @@ REPLServer.prototype.createContext = function() { Object.defineProperty(context, 'console', { configurable: true, writable: true, + enumerable: false, value: _console }); @@ -838,11 +844,13 @@ REPLServer.prototype.createContext = function() { Object.defineProperty(context, 'module', { configurable: true, writable: true, + enumerable: false, value: module }); Object.defineProperty(context, 'require', { configurable: true, writable: true, + enumerable: false, value: makeRequireFunction(module) }); diff --git a/lib/string_decoder.js b/lib/string_decoder.js index b460da19840c..897aa2bd94dc 100644 --- a/lib/string_decoder.js +++ b/lib/string_decoder.js @@ -63,7 +63,12 @@ for (var i = 0; i < encodings.length; ++i) // characters. function StringDecoder(encoding) { this.encoding = normalizeEncoding(encoding); - this[kNativeDecoder] = Buffer.alloc(kSize); + Object.defineProperty(this, kNativeDecoder, { + value: Buffer.alloc(kSize), + configurable: true, + writable: true, + enumerable: false + }); this[kNativeDecoder][kEncodingField] = encodingsMap[this.encoding]; } diff --git a/lib/trace_events.js b/lib/trace_events.js index 878580c67f5a..bf69d51afe52 100644 --- a/lib/trace_events.js +++ b/lib/trace_events.js @@ -25,9 +25,16 @@ const enabledTracingObjects = new Set(); class Tracing { constructor(categories) { - this[kHandle] = new CategorySet(categories); - this[kCategories] = categories; - this[kEnabled] = false; + const attributes = { + configurable: true, + writable: true, + enumerable: false + }; + Object.defineProperties(this, { + [kHandle]: { ...attributes, value: new CategorySet(categories) }, + [kCategories]: { ...attributes, value: categories }, + [kEnabled]: { ...attributes, value: false } + }); } enable() {