| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 034ba73 commit 2bf46ae
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -416,6 +416,55 @@ generate a core file. | |||
| 416 | 416 | ||
| 417 | 417 | This feature is not available in [`Worker`][] threads. | |
| 418 | 418 | ||
| 419 | + ## process.allowedNodeEnvironmentFlags | ||
| 420 | + <!-- YAML | ||
| 421 | + added: REPLACEME | ||
| 422 | + --> | ||
| 423 | + | ||
| 424 | + * {Set} | ||
| 425 | + | ||
| 426 | + The `process.allowedNodeEnvironmentFlags` property is a special, | ||
| 427 | + read-only `Set` of flags allowable within the [`NODE_OPTIONS`][] | ||
| 428 | + environment variable. | ||
| 429 | + | ||
| 430 | + `process.allowedNodeEnvironmentFlags` extends `Set`, but overrides | ||
| 431 | + `Set.prototype.has` to recognize several different possible flag | ||
| 432 | + representations. `process.allowedNodeEnvironmentFlags.has()` will | ||
| 433 | + return `true` in the following cases: | ||
| 434 | + | ||
| 435 | + - Flags may omit leading single (`-`) or double (`--`) dashes; e.g., | ||
| 436 | + `inspect-brk` for `--inspect-brk`, or `r` for `-r`. | ||
| 437 | + - Flags passed through to V8 (as listed in `--v8-options`) may replace | ||
| 438 | + one or more *non-leading* dashes for an underscore, or vice-versa; | ||
| 439 | + e.g., `--perf_basic_prof`, `--perf-basic-prof`, `--perf_basic-prof`, | ||
| 440 | + etc. | ||
| 441 | + - Flags may contain one or more equals (`=`) characters; all | ||
| 442 | + characters after and including the first equals will be ignored; | ||
| 443 | + e.g., `--stack-trace-limit=100`. | ||
| 444 | + - Flags *must* be allowable within [`NODE_OPTIONS`][]. | ||
| 445 | + | ||
| 446 | + When iterating over `process.allowedNodeEnvironmentFlags`, flags will | ||
| 447 | + appear only *once*; each will begin with one or more dashes. Flags | ||
| 448 | + passed through to V8 will contain underscores instead of non-leading | ||
| 449 | + dashes: | ||
| 450 | + | ||
| 451 | + ```js | ||
| 452 | + process.allowedNodeEnvironmentFlags.forEach((flag) => { | ||
| 453 | + // -r | ||
| 454 | + // --inspect-brk | ||
| 455 | + // --abort_on_uncaught_exception | ||
| 456 | + // ... | ||
| 457 | + }); | ||
| 458 | + ``` | ||
| 459 | + | ||
| 460 | + The methods `add()`, `clear()`, and `delete()` of | ||
| 461 | + `process.allowedNodeEnvironmentFlags` do nothing, and will fail | ||
| 462 | + silently. | ||
| 463 | + | ||
| 464 | + If Node.js was compiled *without* [`NODE_OPTIONS`][] support (shown in | ||
| 465 | + [`process.config`][]), `process.allowedNodeEnvironmentFlags` will | ||
| 466 | + contain what *would have* been allowable. | ||
| 467 | + | ||
| 419 | 468 | ## process.arch | |
| 420 | 469 | <!-- YAML | |
| 421 | 470 | added: v0.5.0 | |
@@ -2061,8 +2110,10 @@ cases: | |||
| 2061 | 2110 | [`end()`]: stream.html#stream_writable_end_chunk_encoding_callback | |
| 2062 | 2111 | [`net.Server`]: net.html#net_class_net_server | |
| 2063 | 2112 | [`net.Socket`]: net.html#net_class_net_socket | |
| 2113 | + [`NODE_OPTIONS`]: cli.html#cli_node_options_options | ||
| 2064 | 2114 | [`os.constants.dlopen`]: os.html#os_dlopen_constants | |
| 2065 | 2115 | [`process.argv`]: #process_process_argv | |
| 2116 | + [`process.config`]: #process_process_config | ||
| 2066 | 2117 | [`process.execPath`]: #process_process_execpath | |
| 2067 | 2118 | [`process.exit()`]: #process_process_exit_code | |
| 2068 | 2119 | [`process.exitCode`]: #process_process_exitcode | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -194,6 +194,8 @@ | |||
| 194 | 194 | ||
| 195 | 195 | perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE); | |
| 196 | 196 | ||
| 197 | + setupAllowedFlags(); | ||
| 198 | + | ||
| 197 | 199 | // There are various modes that Node can run in. The most common two | |
| 198 | 200 | // are running from a script and running the REPL - but there are a few | |
| 199 | 201 | // others like the debugger or running --eval arguments. Here we decide | |
@@ -593,5 +595,92 @@ | |||
| 593 | 595 | new vm.Script(source, { displayErrors: true, filename }); | |
| 594 | 596 | } | |
| 595 | 597 | ||
| 598 | + function setupAllowedFlags() { | ||
| 599 | + // This builds process.allowedNodeEnvironmentFlags | ||
| 600 | + // from data in the config binding | ||
| 601 | + | ||
| 602 | + const replaceDashesRegex = /-/g; | ||
| 603 | + const leadingDashesRegex = /^--?/; | ||
| 604 | + const trailingValuesRegex = /=.*$/; | ||
| 605 | + | ||
| 606 | + // Save references so user code does not interfere | ||
| 607 | + const replace = Function.call.bind(String.prototype.replace); | ||
| 608 | + const has = Function.call.bind(Set.prototype.has); | ||
| 609 | + const test = Function.call.bind(RegExp.prototype.test); | ||
| 610 | + | ||
| 611 | + const { | ||
| 612 | + allowedV8EnvironmentFlags, | ||
| 613 | + allowedNodeEnvironmentFlags | ||
| 614 | + } = process.binding('config'); | ||
| 615 | + | ||
| 616 | + const trimLeadingDashes = (flag) => replace(flag, leadingDashesRegex, ''); | ||
| 617 | + | ||
| 618 | + // Save these for comparison against flags provided to | ||
| 619 | + // process.allowedNodeEnvironmentFlags.has() which lack leading dashes. | ||
| 620 | + // Avoid interference w/ user code by flattening `Set.prototype` into | ||
| 621 | + // each object. | ||
| 622 | + const [nodeFlags, v8Flags] = [ | ||
| 623 | + allowedNodeEnvironmentFlags, allowedV8EnvironmentFlags | ||
| 624 | + ].map((flags) => Object.defineProperties( | ||
| 625 | + new Set(flags.map(trimLeadingDashes)), | ||
| 626 | + Object.getOwnPropertyDescriptors(Set.prototype)) | ||
| 627 | + ); | ||
| 628 | + | ||
| 629 | + class NodeEnvironmentFlagsSet extends Set { | ||
| 630 | + constructor(...args) { | ||
| 631 | + super(...args); | ||
| 632 | + | ||
| 633 | + // the super constructor consumes `add`, but | ||
| 634 | + // disallow any future adds. | ||
| 635 | + this.add = () => this; | ||
| 636 | + } | ||
| 637 | + | ||
| 638 | + delete() { | ||
| 639 | + // noop, `Set` API compatible | ||
| 640 | + return false; | ||
| 641 | + } | ||
| 642 | + | ||
| 643 | + clear() { | ||
| 644 | + // noop | ||
| 645 | + } | ||
| 646 | + | ||
| 647 | + has(key) { | ||
| 648 | + // This will return `true` based on various possible | ||
| 649 | + // permutations of a flag, including present/missing leading | ||
| 650 | + // dash(es) and/or underscores-for-dashes in the case of V8-specific | ||
| 651 | + // flags. Strips any values after `=`, inclusive. | ||
| 652 | + if (typeof key === 'string') { | ||
| 653 | + key = replace(key, trailingValuesRegex, ''); | ||
| 654 | + if (test(leadingDashesRegex, key)) { | ||
| 655 | + return has(this, key) || | ||
| 656 | + has(v8Flags, | ||
| 657 | + replace( | ||
| 658 | + replace( | ||
| 659 | + key, | ||
| 660 | + leadingDashesRegex, | ||
| 661 | + '' | ||
| 662 | + ), | ||
| 663 | + replaceDashesRegex, | ||
| 664 | + '_' | ||
| 665 | + ) | ||
| 666 | + ); | ||
| 667 | + } | ||
| 668 | + return has(nodeFlags, key) || | ||
| 669 | + has(v8Flags, replace(key, replaceDashesRegex, '_')); | ||
| 670 | + } | ||
| 671 | + return false; | ||
| 672 | + } | ||
| 673 | + } | ||
| 674 | + | ||
| 675 | + Object.freeze(NodeEnvironmentFlagsSet.prototype.constructor); | ||
| 676 | + Object.freeze(NodeEnvironmentFlagsSet.prototype); | ||
| 677 | + | ||
| 678 | + process.allowedNodeEnvironmentFlags = Object.freeze( | ||
| 679 | + new NodeEnvironmentFlagsSet( | ||
| 680 | + allowedNodeEnvironmentFlags.concat(allowedV8EnvironmentFlags) | ||
| 681 | + ) | ||
| 682 | + ); | ||
| 683 | + } | ||
| 684 | + | ||
| 596 | 685 | startup(); | |
| 597 | 686 | }); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -587,6 +587,68 @@ const char* signo_string(int signo) { | |||
| 587 | 587 | } | |
| 588 | 588 | } | |
| 589 | 589 | ||
| 590 | + // These are all flags available for use with NODE_OPTIONS. | ||
| 591 | + // | ||
| 592 | + // Disallowed flags: | ||
| 593 | + // These flags cause Node to do things other than run scripts: | ||
| 594 | + // --version / -v | ||
| 595 | + // --eval / -e | ||
| 596 | + // --print / -p | ||
| 597 | + // --check / -c | ||
| 598 | + // --interactive / -i | ||
| 599 | + // --prof-process | ||
| 600 | + // --v8-options | ||
| 601 | + // These flags are disallowed because security: | ||
| 602 | + // --preserve-symlinks | ||
| 603 | + const char* const environment_flags[] = { | ||
| 604 | + // Node options, sorted in `node --help` order for ease of comparison. | ||
| 605 | + "--enable-fips", | ||
| 606 | + "--experimental-modules", | ||
| 607 | + "--experimenatl-repl-await", | ||
| 608 | + "--experimental-vm-modules", | ||
| 609 | + "--experimental-worker", | ||
| 610 | + "--force-fips", | ||
| 611 | + "--icu-data-dir", | ||
| 612 | + "--inspect", | ||
| 613 | + "--inspect-brk", | ||
| 614 | + "--inspect-port", | ||
| 615 | + "--loader", | ||
| 616 | + "--napi-modules", | ||
| 617 | + "--no-deprecation", | ||
| 618 | + "--no-force-async-hooks-checks", | ||
| 619 | + "--no-warnings", | ||
| 620 | + "--openssl-config", | ||
| 621 | + "--pending-deprecation", | ||
| 622 | + "--redirect-warnings", | ||
| 623 | + "--require", | ||
| 624 | + "--throw-deprecation", | ||
| 625 | + "--tls-cipher-list", | ||
| 626 | + "--trace-deprecation", | ||
| 627 | + "--trace-event-categories", | ||
| 628 | + "--trace-event-file-pattern", | ||
| 629 | + "--trace-events-enabled", | ||
| 630 | + "--trace-sync-io", | ||
| 631 | + "--trace-warnings", | ||
| 632 | + "--track-heap-objects", | ||
| 633 | + "--use-bundled-ca", | ||
| 634 | + "--use-openssl-ca", | ||
| 635 | + "--v8-pool-size", | ||
| 636 | + "--zero-fill-buffers", | ||
| 637 | + "-r" | ||
| 638 | + }; | ||
| 639 | + | ||
| 640 | + // V8 options (define with '_', which allows '-' or '_') | ||
| 641 | + const char* const v8_environment_flags[] = { | ||
| 642 | + "--abort_on_uncaught_exception", | ||
| 643 | + "--max_old_space_size", | ||
| 644 | + "--perf_basic_prof", | ||
| 645 | + "--perf_prof", | ||
| 646 | + "--stack_trace_limit", | ||
| 647 | + }; | ||
| 648 | + | ||
| 649 | + int v8_environment_flags_count = arraysize(v8_environment_flags); | ||
| 650 | + int environment_flags_count = arraysize(environment_flags); | ||
| 651 | + | ||
| 590 | 652 | // Look up environment variable unless running as setuid root. | |
| 591 | 653 | bool SafeGetenv(const char* key, std::string* text) { | |
| 592 | 654 | #if !defined(__CloudABI__) && !defined(_WIN32) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | 6 | namespace node { | |
| 7 | 7 | ||
| 8 | + using v8::Array; | ||
| 8 | 9 | using v8::Boolean; | |
| 9 | 10 | using v8::Context; | |
| 10 | 11 | using v8::Integer; | |
@@ -132,6 +133,22 @@ static void Initialize(Local<Object> target, | |||
| 132 | 133 | READONLY_PROPERTY(debug_options_obj, | |
| 133 | 134 | "inspectorEnabled", | |
| 134 | 135 | Boolean::New(isolate, debug_options->inspector_enabled)); | |
| 136 | + | ||
| 137 | + Local<Array> environmentFlags = Array::New(env->isolate(), | ||
| 138 | + environment_flags_count); | ||
| 139 | + READONLY_PROPERTY(target, "allowedNodeEnvironmentFlags", environmentFlags); | ||
| 140 | + for (int i = 0; i < environment_flags_count; ++i) { | ||
| 141 | + environmentFlags->Set(i, OneByteString(env->isolate(), | ||
| 142 | + environment_flags[i])); | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | + Local<Array> v8EnvironmentFlags = Array::New(env->isolate(), | ||
| 146 | + v8_environment_flags_count); | ||
| 147 | + READONLY_PROPERTY(target, "allowedV8EnvironmentFlags", v8EnvironmentFlags); | ||
| 148 | + for (int i = 0; i < v8_environment_flags_count; ++i) { | ||
| 149 | + v8EnvironmentFlags->Set(i, OneByteString(env->isolate(), | ||
| 150 | + v8_environment_flags[i])); | ||
| 151 | + } | ||
| 135 | 152 | } // InitConfig | |
| 136 | 153 | ||
| 137 | 154 | } // namespace node | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -178,6 +178,11 @@ extern bool v8_initialized; | |||
| 178 | 178 | ||
| 179 | 179 | extern std::shared_ptr<PerProcessOptions> per_process_opts; | |
| 180 | 180 | ||
| 181 | + extern const char* const environment_flags[]; | ||
| 182 | + extern int environment_flags_count; | ||
| 183 | + extern const char* const v8_environment_flags[]; | ||
| 184 | + extern int v8_environment_flags_count; | ||
| 185 | + | ||
| 181 | 186 | // Forward declaration | |
| 182 | 187 | class Environment; | |
| 183 | 188 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,74 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const assert = require('assert'); | ||
| 4 | + require('../common'); | ||
| 5 | + | ||
| 6 | + // assert legit flags are allowed, and bogus flags are disallowed | ||
| 7 | + { | ||
| 8 | + const goodFlags = [ | ||
| 9 | + '--inspect-brk', | ||
| 10 | + 'inspect-brk', | ||
| 11 | + '--perf_basic_prof', | ||
| 12 | + '--perf-basic-prof', | ||
| 13 | + 'perf-basic-prof', | ||
| 14 | + '--perf_basic-prof', | ||
| 15 | + 'perf_basic-prof', | ||
| 16 | + 'perf_basic_prof', | ||
| 17 | + '-r', | ||
| 18 | + 'r', | ||
| 19 | + '--stack-trace-limit=100', | ||
| 20 | + '--stack-trace-limit=-=xX_nodejs_Xx=-' | ||
| 21 | + ]; | ||
| 22 | + | ||
| 23 | + const badFlags = [ | ||
| 24 | + '--inspect_brk', | ||
| 25 | + 'INSPECT-BRK', | ||
| 26 | + '--INSPECT-BRK', | ||
| 27 | + '--r', | ||
| 28 | + '-R', | ||
| 29 | + '---inspect-brk', | ||
| 30 | + '--cheeseburgers' | ||
| 31 | + ]; | ||
| 32 | + | ||
| 33 | + goodFlags.forEach((flag) => { | ||
| 34 | + assert.strictEqual( | ||
| 35 | + process.allowedNodeEnvironmentFlags.has(flag), | ||
| 36 | + true, | ||
| 37 | + `flag should be in set: ${flag}` | ||
| 38 | + ); | ||
| 39 | + }); | ||
| 40 | + | ||
| 41 | + badFlags.forEach((flag) => { | ||
| 42 | + assert.strictEqual( | ||
| 43 | + process.allowedNodeEnvironmentFlags.has(flag), | ||
| 44 | + false, | ||
| 45 | + `flag should not be in set: ${flag}` | ||
| 46 | + ); | ||
| 47 | + }); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + // assert all "canonical" flags begin with dash(es) | ||
| 51 | + { | ||
| 52 | + process.allowedNodeEnvironmentFlags.forEach((flag) => { | ||
| 53 | + assert.strictEqual(/^--?[a-z8_-]+$/.test(flag), true); | ||
| 54 | + }); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + // assert immutability of process.allowedNodeEnvironmentFlags | ||
| 58 | + { | ||
| 59 | + assert.strictEqual(Object.isFrozen(process.allowedNodeEnvironmentFlags), | ||
| 60 | + true); | ||
| 61 | + | ||
| 62 | + process.allowedNodeEnvironmentFlags.add('foo'); | ||
| 63 | + assert.strictEqual(process.allowedNodeEnvironmentFlags.has('foo'), false); | ||
| 64 | + process.allowedNodeEnvironmentFlags.forEach((flag) => { | ||
| 65 | + assert.strictEqual(flag === 'foo', false); | ||
| 66 | + }); | ||
| 67 | + | ||
| 68 | + process.allowedNodeEnvironmentFlags.clear(); | ||
| 69 | + assert.strictEqual(process.allowedNodeEnvironmentFlags.size > 0, true); | ||
| 70 | + | ||
| 71 | + const size = process.allowedNodeEnvironmentFlags.size; | ||
| 72 | + process.allowedNodeEnvironmentFlags.delete('-r'); | ||
| 73 | + assert.strictEqual(process.allowedNodeEnvironmentFlags.size, size); | ||
| 74 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,7 +16,7 @@ const jsPrimitives = { | |||
| 16 | 16 | const jsGlobalObjectsUrl = `${jsDocPrefix}Reference/Global_Objects/`; | |
| 17 | 17 | const jsGlobalTypes = [ | |
| 18 | 18 | 'Array', 'ArrayBuffer', 'DataView', 'Date', 'Error', 'EvalError', 'Function', | |
| 19 | - 'Object', 'Promise', 'RangeError', 'ReferenceError', 'RegExp', | ||
| 19 | + 'Object', 'Promise', 'RangeError', 'ReferenceError', 'RegExp', 'Set', | ||
| 20 | 20 | 'SharedArrayBuffer', 'SyntaxError', 'TypeError', 'TypedArray', 'URIError', | |
| 21 | 21 | 'Uint8Array', | |
| 22 | 22 | ]; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments