diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 624360c4fc7e0..02c5ccb08970e 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -66,6 +66,7 @@ import { IncompleteCompletionsCache, IndentStyle, isArray, + isExternalModuleNameRelative, isIgnoredFileFromWildCardWatching, isInsideNodeModules, isJsonEqual, @@ -89,7 +90,6 @@ import { ParsedCommandLine, parseJsonSourceFileConfigFileContent, parseJsonText, - parsePackageName, Path, PerformanceEvent, PluginImport, @@ -4487,7 +4487,11 @@ export class ProjectService { } this.logger.info(`Enabling plugin ${pluginConfigEntry.name} from candidate paths: ${searchPaths.join(",")}`); - if (!pluginConfigEntry.name || parsePackageName(pluginConfigEntry.name).rest) { + if ( + !pluginConfigEntry.name || + isExternalModuleNameRelative(pluginConfigEntry.name) || + /[\\/]\.\.?($|[\\/])/.test(pluginConfigEntry.name) + ) { this.logger.info(`Skipped loading plugin ${pluginConfigEntry.name || JSON.stringify(pluginConfigEntry)} because only package name is allowed plugin name`); return; } diff --git a/src/testRunner/unittests/tsserver/plugins.ts b/src/testRunner/unittests/tsserver/plugins.ts index f984abc93774f..3a6f755f86021 100644 --- a/src/testRunner/unittests/tsserver/plugins.ts +++ b/src/testRunner/unittests/tsserver/plugins.ts @@ -45,8 +45,20 @@ describe("unittests:: tsserver:: plugins:: loading", () => { } it("With local plugins", () => { - const expectedToLoad = ["@myscoped/plugin", "unscopedPlugin"]; - const notToLoad = ["../myPlugin", "myPlugin/../malicious"]; + const expectedToLoad = [ + "@myscoped/plugin", + "@myscoped/plugin/subpath", + "@myscoped/plugin/sub/path", + "unscopedPlugin", + "unscopedPlugin/subpath", + "unscopedPlugin/sub/path", + ]; + const notToLoad = [ + "../myPlugin", + "@myscoped/plugin/../malicious", + "myPlugin/../malicious", + "myPlugin/subpath/../../malicious", + ]; const aTs: File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` }; const tsconfig: File = { path: "/tsconfig.json", @@ -65,8 +77,20 @@ describe("unittests:: tsserver:: plugins:: loading", () => { }); it("With global plugins", () => { - const expectedToLoad = ["@myscoped/plugin", "unscopedPlugin"]; - const notToLoad = ["../myPlugin", "myPlugin/../malicious"]; + const expectedToLoad = [ + "@myscoped/plugin", + "@myscoped/plugin/subpath", + "@myscoped/plugin/sub/path", + "unscopedPlugin", + "unscopedPlugin/subpath", + "unscopedPlugin/sub/path", + ]; + const notToLoad = [ + "../myPlugin", + "@myscoped/plugin/../malicious", + "myPlugin/../malicious", + "myPlugin/subpath/../../malicious", + ]; const aTs: File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` }; const tsconfig: File = { path: "/tsconfig.json", diff --git a/tests/baselines/reference/tsserver/plugins/With-global-plugins.js b/tests/baselines/reference/tsserver/plugins/With-global-plugins.js index f170d952d37d6..f3027f9236829 100644 --- a/tests/baselines/reference/tsserver/plugins/With-global-plugins.js +++ b/tests/baselines/reference/tsserver/plugins/With-global-plugins.js @@ -60,17 +60,43 @@ Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin from candidate paths: Info seq [hh:mm:ss:mss] Loading @myscoped/plugin from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) Loading plugin: @myscoped/plugin Info seq [hh:mm:ss:mss] Plugin validation succeeded +Info seq [hh:mm:ss:mss] Loading global plugin @myscoped/plugin/subpath +Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin/subpath from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Loading @myscoped/plugin/subpath from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +Loading plugin: @myscoped/plugin/subpath +Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand" +Info seq [hh:mm:ss:mss] Loading global plugin @myscoped/plugin/sub/path +Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin/sub/path from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Loading @myscoped/plugin/sub/path from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +Loading plugin: @myscoped/plugin/sub/path +Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand" Info seq [hh:mm:ss:mss] Loading global plugin unscopedPlugin Info seq [hh:mm:ss:mss] Enabling plugin unscopedPlugin from candidate paths: /a/lib/tsc.js/../../.. Info seq [hh:mm:ss:mss] Loading unscopedPlugin from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) Loading plugin: unscopedPlugin Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand" +Info seq [hh:mm:ss:mss] Loading global plugin unscopedPlugin/subpath +Info seq [hh:mm:ss:mss] Enabling plugin unscopedPlugin/subpath from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Loading unscopedPlugin/subpath from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +Loading plugin: unscopedPlugin/subpath +Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand" +Info seq [hh:mm:ss:mss] Loading global plugin unscopedPlugin/sub/path +Info seq [hh:mm:ss:mss] Enabling plugin unscopedPlugin/sub/path from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Loading unscopedPlugin/sub/path from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +Loading plugin: unscopedPlugin/sub/path +Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand" Info seq [hh:mm:ss:mss] Loading global plugin ../myPlugin Info seq [hh:mm:ss:mss] Enabling plugin ../myPlugin from candidate paths: /a/lib/tsc.js/../../.. Info seq [hh:mm:ss:mss] Skipped loading plugin ../myPlugin because only package name is allowed plugin name +Info seq [hh:mm:ss:mss] Loading global plugin @myscoped/plugin/../malicious +Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin/../malicious from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Skipped loading plugin @myscoped/plugin/../malicious because only package name is allowed plugin name Info seq [hh:mm:ss:mss] Loading global plugin myPlugin/../malicious Info seq [hh:mm:ss:mss] Enabling plugin myPlugin/../malicious from candidate paths: /a/lib/tsc.js/../../.. Info seq [hh:mm:ss:mss] Skipped loading plugin myPlugin/../malicious because only package name is allowed plugin name +Info seq [hh:mm:ss:mss] Loading global plugin myPlugin/subpath/../../malicious +Info seq [hh:mm:ss:mss] Enabling plugin myPlugin/subpath/../../malicious from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Skipped loading plugin myPlugin/subpath/../../malicious because only package name is allowed plugin name Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms diff --git a/tests/baselines/reference/tsserver/plugins/With-local-plugins.js b/tests/baselines/reference/tsserver/plugins/With-local-plugins.js index 65cf96c9cef6b..206bfa2a917be 100644 --- a/tests/baselines/reference/tsserver/plugins/With-local-plugins.js +++ b/tests/baselines/reference/tsserver/plugins/With-local-plugins.js @@ -11,15 +11,33 @@ class c { prop = "hello"; foo() { return this.prop; } } { "name": "@myscoped/plugin" }, + { + "name": "@myscoped/plugin/subpath" + }, + { + "name": "@myscoped/plugin/sub/path" + }, { "name": "unscopedPlugin" }, + { + "name": "unscopedPlugin/subpath" + }, + { + "name": "unscopedPlugin/sub/path" + }, { "name": "../myPlugin" }, + { + "name": "@myscoped/plugin/../malicious" + }, { "name": "myPlugin/../malicious" }, + { + "name": "myPlugin/subpath/../../malicious" + }, { "transform": "some-transform" } @@ -74,15 +92,33 @@ Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { { "name": "@myscoped/plugin" }, + { + "name": "@myscoped/plugin/subpath" + }, + { + "name": "@myscoped/plugin/sub/path" + }, { "name": "unscopedPlugin" }, + { + "name": "unscopedPlugin/subpath" + }, + { + "name": "unscopedPlugin/sub/path" + }, { "name": "../myPlugin" }, + { + "name": "@myscoped/plugin/../malicious" + }, { "name": "myPlugin/../malicious" }, + { + "name": "myPlugin/subpath/../../malicious" + }, { "transform": "some-transform" } @@ -96,14 +132,34 @@ Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin from candidate paths: Info seq [hh:mm:ss:mss] Loading @myscoped/plugin from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) Loading plugin: @myscoped/plugin Info seq [hh:mm:ss:mss] Plugin validation succeeded +Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin/subpath from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Loading @myscoped/plugin/subpath from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +Loading plugin: @myscoped/plugin/subpath +Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand" +Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin/sub/path from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Loading @myscoped/plugin/sub/path from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +Loading plugin: @myscoped/plugin/sub/path +Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand" Info seq [hh:mm:ss:mss] Enabling plugin unscopedPlugin from candidate paths: /a/lib/tsc.js/../../.. Info seq [hh:mm:ss:mss] Loading unscopedPlugin from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) Loading plugin: unscopedPlugin Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand" +Info seq [hh:mm:ss:mss] Enabling plugin unscopedPlugin/subpath from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Loading unscopedPlugin/subpath from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +Loading plugin: unscopedPlugin/subpath +Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand" +Info seq [hh:mm:ss:mss] Enabling plugin unscopedPlugin/sub/path from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Loading unscopedPlugin/sub/path from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +Loading plugin: unscopedPlugin/sub/path +Info seq [hh:mm:ss:mss] Plugin activation failed: Error: Protocol handler already exists for command "testProtocolCommand" Info seq [hh:mm:ss:mss] Enabling plugin ../myPlugin from candidate paths: /a/lib/tsc.js/../../.. Info seq [hh:mm:ss:mss] Skipped loading plugin ../myPlugin because only package name is allowed plugin name +Info seq [hh:mm:ss:mss] Enabling plugin @myscoped/plugin/../malicious from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Skipped loading plugin @myscoped/plugin/../malicious because only package name is allowed plugin name Info seq [hh:mm:ss:mss] Enabling plugin myPlugin/../malicious from candidate paths: /a/lib/tsc.js/../../.. Info seq [hh:mm:ss:mss] Skipped loading plugin myPlugin/../malicious because only package name is allowed plugin name +Info seq [hh:mm:ss:mss] Enabling plugin myPlugin/subpath/../../malicious from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Skipped loading plugin myPlugin/subpath/../../malicious because only package name is allowed plugin name Info seq [hh:mm:ss:mss] Enabling plugin undefined from candidate paths: /a/lib/tsc.js/../../.. Info seq [hh:mm:ss:mss] Skipped loading plugin {"transform":"some-transform"} because only package name is allowed plugin name Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined WatchType: Closed Script info @@ -155,6 +211,12 @@ Info seq [hh:mm:ss:mss] event: }, "compilerOptions": { "plugins": [ + "", + "", + "", + "", + "", + "", "", "", "",