From faf7c98bd5ff397ab395104f77e8fd76c2547810 Mon Sep 17 00:00:00 2001 From: v7ea Date: Thu, 16 Nov 2023 16:48:07 +0800 Subject: [PATCH] security patch for high severity CVEs (i.e., CVE-2023-36742 & CVE-2022-41034 & CVE-2023-24893) --- .../src/features/packageJSONContribution.ts | 7 ++- extensions/npm/src/npmMain.ts | 2 +- .../view/renderers/backLayerWebView.ts | 58 +++++++++---------- .../terminal/browser/xterm/decorationAddon.ts | 15 ++++- 4 files changed, 45 insertions(+), 37 deletions(-) diff --git a/extensions/npm/src/features/packageJSONContribution.ts b/extensions/npm/src/features/packageJSONContribution.ts index ad638d7d..3bf60bea 100644 --- a/extensions/npm/src/features/packageJSONContribution.ts +++ b/extensions/npm/src/features/packageJSONContribution.ts @@ -254,10 +254,11 @@ export class PackageJSONContribution implements IJSONContribution { private isValidNPMName(name: string): boolean { // following rules from https://github.com/npm/validate-npm-package-name - if (!name || name.length > 214 || name.match(/^[_.]/)) { + // leading slash added as additional security measure + if (!name || name.length > 214 || name.match(/^[-_.\s]/)) { return false; } - const match = name.match(/^(?:@([^/]+?)[/])?([^/]+?)$/); + const match = name.match(/^(?:@([^/~\s)('!*]+?)[/])?([^/~)('!*\s]+?)$/); if (match) { const scope = match[1]; if (scope && encodeURIComponent(scope) !== scope) { @@ -285,7 +286,7 @@ export class PackageJSONContribution implements IJSONContribution { private npmView(npmCommandPath: string, pack: string, resource: Uri | undefined): Promise { return new Promise((resolve, _reject) => { - const args = ['view', '--json', pack, 'description', 'dist-tags.latest', 'homepage', 'version']; + const args = ['view', '--json', '--', pack, 'description', 'dist-tags.latest', 'homepage', 'version', 'time']; let cwd = resource && resource.scheme === 'file' ? dirname(resource.fsPath) : undefined; cp.execFile(npmCommandPath, args, { cwd }, (error, stdout) => { if (!error) { diff --git a/extensions/npm/src/npmMain.ts b/extensions/npm/src/npmMain.ts index 3788c94e..5b0cd737 100644 --- a/extensions/npm/src/npmMain.ts +++ b/extensions/npm/src/npmMain.ts @@ -73,7 +73,7 @@ export async function activate(context: vscode.ExtensionContext): Promise } async function getNPMCommandPath(): Promise { - if (canRunNpmInCurrentWorkspace()) { + if (vscode.workspace.isTrusted && canRunNpmInCurrentWorkspace()) { try { return await which(process.platform === 'win32' ? 'npm.cmd' : 'npm'); } catch (e) { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index dedbe999..120c9c87 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -542,24 +542,8 @@ var requirejs = (function() { return; } - if (matchesScheme(link, Schemas.command)) { - const ret = /command\:workbench\.action\.openLargeOutput\?(.*)/.exec(link); - if (ret && ret.length === 2) { - const outputId = ret[1]; - this.openerService.open(CellUri.generateCellOutputUri(this.documentUri, outputId)); - return; - } - console.warn('Command links are deprecated and will be removed, use message passing instead: https://github.com/microsoft/vscode/issues/123601'); - } - - if (matchesScheme(link, Schemas.command)) { - if (this.workspaceTrustManagementService.isWorkspaceTrusted()) { - this.openerService.open(link, { fromUserGesture: true, allowContributedOpeners: true, allowCommands: true }); - } else { - console.warn('Command links are disabled in untrusted workspaces'); - } - } else if (matchesSomeScheme(link, Schemas.vscodeNotebookCell, Schemas.http, Schemas.https, Schemas.mailto)) { - this.openerService.open(link, { fromUserGesture: true, allowContributedOpeners: true, allowCommands: true }); + if (matchesSomeScheme(link, Schemas.vscodeNotebookCell, Schemas.http, Schemas.https, Schemas.mailto)) { + this.openerService.open(link, { fromUserGesture: true, allowContributedOpeners: true, allowCommands: false }); } })); @@ -670,23 +654,35 @@ var requirejs = (function() { } case 'clicked-link': { let linkToOpen: URI | string | undefined; + if (matchesScheme(data.href, Schemas.command)) { - const ret = /command\:workbench\.action\.openLargeOutput\?(.*)/.exec(data.href); - if (ret && ret.length === 2) { - const outputId = ret[1]; - const group = this.editorGroupService.activeGroup; - - if (group) { - if (group.activeEditor) { - group.pinEditor(group.activeEditor); + // We allow a very limited set of commands + const uri = URI.parse(data.href); + switch (uri.path) { + case 'workbench.action.openLargeOutput': { + const outputId = uri.query; + const group = this.editorGroupService.activeGroup; + if (group) { + if (group.activeEditor) { + group.pinEditor(group.activeEditor); + } } - } - this.openerService.open(CellUri.generateCellOutputUri(this.documentUri, outputId)); - return; + this.openerService.open(CellUri.generateCellOutputUri(this.documentUri, outputId)); + return; + } + case 'github-issues.authNow': + case 'workbench.extensions.search': + case 'workbench.action.openSettings': { + this.openerService.open(data.href, { fromUserGesture: true, allowCommands: true, fromWorkspace: true }); + return; + } } + + return; } - if (matchesSomeScheme(data.href, Schemas.http, Schemas.https, Schemas.mailto, Schemas.command, Schemas.vscodeNotebookCell, Schemas.vscodeNotebook)) { + + if (matchesSomeScheme(data.href, Schemas.http, Schemas.https, Schemas.mailto, Schemas.vscodeNotebookCell, Schemas.vscodeNotebook)) { linkToOpen = data.href; } else if (!/^[\w\-]+:/.test(data.href)) { const fragmentStartIndex = data.href.lastIndexOf('#'); @@ -717,7 +713,7 @@ var requirejs = (function() { } if (linkToOpen) { - this.openerService.open(linkToOpen, { fromUserGesture: true, allowCommands: true }); + this.openerService.open(linkToOpen, { fromUserGesture: true, allowCommands: false }); } break; } diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts index 4caf924b..a0c614ce 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts @@ -24,6 +24,8 @@ import { TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { TERMINAL_COMMAND_DECORATION_DEFAULT_BACKGROUND_COLOR, TERMINAL_COMMAND_DECORATION_ERROR_BACKGROUND_COLOR, TERMINAL_COMMAND_DECORATION_SUCCESS_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { Color } from 'vs/base/common/color'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; + const enum DecorationSelector { CommandDecoration = 'terminal-command-decoration', @@ -59,7 +61,8 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { @IHoverService private readonly _hoverService: IHoverService, @IConfigurationService private readonly _configurationService: IConfigurationService, @IThemeService private readonly _themeService: IThemeService, - @IOpenerService private readonly _openerService: IOpenerService + @IOpenerService private readonly _openerService: IOpenerService, + @INotificationService private readonly _notificationService: INotificationService ) { super(); this._register(toDisposable(() => this._dispose())); @@ -330,7 +333,15 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { } actions.push({ class: 'rerun-command', tooltip: 'Rerun Command', dispose: () => { }, id: 'terminal.rerunCommand', label: localize("terminal.rerunCommand", 'Rerun Command'), enabled: true, - run: () => this._onDidRequestRunCommand.fire({ command }) + run: async () => { + this._notificationService.prompt(Severity.Info, localize('rerun', 'Do you want to run the command: {0}', command.command), [{ + label: localize('yes', 'Yes'), + run: () => this._onDidRequestRunCommand.fire({ command }) + }, { + label: localize('no', 'No'), + run: () => { } + }]); + } }); actions.push({ class: 'how-does-this-work', tooltip: 'How does this work?', dispose: () => { }, id: 'terminal.howDoesThisWork', label: localize("terminal.howDoesThisWork", 'How does this work?'), enabled: true,