From 6a995c4f4cc2ced6e3237749973982e751cb0bf9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 4 May 2023 11:13:35 +0200 Subject: [PATCH] unc - adopt setting and handling of allow list (#5) * unc - adopt setting and handling of allow list * unc - set allow list on server too * unc - pick our patched node.js for now * bump electron * unc - ignore sync is not needed with machine scope * unc - use process set directly * :up: 22.5.1 --- build/gulpfile.reh.js | 2 +- build/lib/electron.js | 12 ++-- build/lib/electron.ts | 4 +- src/vs/base/common/errorMessage.ts | 5 ++ src/vs/base/node/unc.ts | 65 +++++++++++++++++++ src/vs/code/electron-main/app.ts | 9 +++ src/vs/code/node/cli.ts | 14 +++- .../files/node/diskFileSystemProvider.ts | 7 +- .../electron-main/utilityProcess.ts | 5 ++ .../electron-main/windowsMainService.ts | 37 ++++++++++- .../node/remoteExtensionHostAgentCli.ts | 8 +++ .../node/remoteExtensionHostAgentServer.ts | 11 ++++ .../browser/workbench.contribution.ts | 19 +++++- src/vs/workbench/common/configuration.ts | 10 ++- .../preferences/browser/settingsLayout.ts | 1 + .../browser/relauncher.contribution.ts | 9 ++- .../browser/workspace.contribution.ts | 7 +- 17 files changed, 203 insertions(+), 22 deletions(-) create mode 100644 src/vs/base/node/unc.ts diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index 4630eaad3cc2c..2e8ef58ef4c46 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -164,7 +164,7 @@ function nodejs(platform, arch) { if (platform === 'win32') { if (product.nodejsRepository) { - return assetFromGithub(product.nodejsRepository, nodeVersion, name => name === `win-${arch}-node.exe`) + return assetFromGithub(product.nodejsRepository, nodeVersion, name => name === `win-${arch}-patched-node.exe`) .pipe(rename('node.exe')); } diff --git a/build/lib/electron.js b/build/lib/electron.js index 02e21d5508b08..686b861edeb59 100644 --- a/build/lib/electron.js +++ b/build/lib/electron.js @@ -76,7 +76,7 @@ function darwinBundleDocumentTypes(types, icon) { }); } exports.config = { - version: product.electronRepository ? '22.4.8' : util.getElectronVersion(), + version: product.electronRepository ? '22.5.1' : util.getElectronVersion(), productAppName: product.nameLong, companyName: 'Microsoft Corporation', copyright: 'Copyright (C) 2023 Microsoft. All rights reserved', @@ -164,10 +164,10 @@ exports.config = { darwinBundleDocumentType([], 'default', 'Folder', ['public.folder']) ], darwinBundleURLTypes: [{ - role: 'Viewer', - name: product.nameLong, - urlSchemes: [product.urlProtocol] - }], + role: 'Viewer', + name: product.nameLong, + urlSchemes: [product.urlProtocol] + }], darwinForceDarkModeSupport: true, darwinCredits: darwinCreditsTemplate ? Buffer.from(darwinCreditsTemplate({ commit: commit, date: new Date().toISOString() })) : undefined, linuxExecutableName: product.applicationName, @@ -193,7 +193,7 @@ function getElectron(arch) { }; } async function main(arch = process.arch) { - const version = product.electronRepository ? '22.4.8' : util.getElectronVersion(); + const version = product.electronRepository ? '22.5.1' : util.getElectronVersion(); const electronPath = path.join(root, '.build', 'electron'); const versionFile = path.join(electronPath, 'version'); const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`; diff --git a/build/lib/electron.ts b/build/lib/electron.ts index b6f1ccea3a409..9e35889c34582 100644 --- a/build/lib/electron.ts +++ b/build/lib/electron.ts @@ -91,7 +91,7 @@ function darwinBundleDocumentTypes(types: { [name: string]: string | string[] }, } export const config = { - version: product.electronRepository ? '22.4.8' : util.getElectronVersion(), + version: product.electronRepository ? '22.5.1' : util.getElectronVersion(), productAppName: product.nameLong, companyName: 'Microsoft Corporation', copyright: 'Copyright (C) 2023 Microsoft. All rights reserved', @@ -212,7 +212,7 @@ function getElectron(arch: string): () => NodeJS.ReadWriteStream { } async function main(arch = process.arch): Promise { - const version = product.electronRepository ? '22.4.8' : util.getElectronVersion(); + const version = product.electronRepository ? '22.5.1' : util.getElectronVersion(); const electronPath = path.join(root, '.build', 'electron'); const versionFile = path.join(electronPath, 'version'); const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`; diff --git a/src/vs/base/common/errorMessage.ts b/src/vs/base/common/errorMessage.ts index eca37716066ac..f16616da430f1 100644 --- a/src/vs/base/common/errorMessage.ts +++ b/src/vs/base/common/errorMessage.ts @@ -26,6 +26,11 @@ function stackToString(stack: string[] | string | undefined): string | undefined function detectSystemErrorMessage(exception: any): string { + // Custom node.js error from us + if (exception.code === 'ERR_UNC_HOST_NOT_ALLOWED') { + return `${exception.message}. Please update the 'security.allowedUNCHosts' setting if you want to allow this host.`; + } + // See https://nodejs.org/api/errors.html#errors_class_system_error if (typeof exception.code === 'string' && typeof exception.errno === 'number' && typeof exception.syscall === 'string') { return nls.localize('nodeExceptionMessage', "A system error occurred ({0})", exception.message); diff --git a/src/vs/base/node/unc.ts b/src/vs/base/node/unc.ts new file mode 100644 index 0000000000000..f5a0a1cda5bbd --- /dev/null +++ b/src/vs/base/node/unc.ts @@ -0,0 +1,65 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { isWindows } from 'vs/base/common/platform'; + +function processUNCHostAllowlist(): Set | undefined { + + // The property `process.uncHostAllowlist` is not available in official node.js + // releases, only in our own builds, so we have to probe for availability + + const processWithUNCHostAllowlist = process as typeof process & { readonly uncHostAllowlist?: Set }; + + return processWithUNCHostAllowlist.uncHostAllowlist; +} + +export function setUNCHostAllowlist(allowedHosts: string[]): void { + if (!isWindows) { + return; + } + + const allowlist = processUNCHostAllowlist(); + if (allowlist) { + allowlist.clear(); + + for (const allowedHost of allowedHosts) { + allowlist.add(allowedHost); + } + } +} + +export function getUNCHostAllowlist(): string[] { + const allowlist = processUNCHostAllowlist(); + if (allowlist) { + return Array.from(allowlist); + } + + return []; +} + +export function addUNCHostToAllowlist(allowedHost: string): void { + if (!isWindows) { + return; + } + + const allowlist = processUNCHostAllowlist(); + if (allowlist) { + allowlist.add(allowedHost); + } +} + +export function toUNCHostAllowlist(arg0: unknown): string[] { + const allowedUNCHosts = new Set(); + + if (Array.isArray(arg0)) { + for (const host of arg0) { + if (typeof host === 'string') { + allowedUNCHosts.add(host); + } + } + } + + return Array.from(allowedUNCHosts); +} diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index f03df1a910498..1f63c26f61e22 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { app, BrowserWindow, dialog, protocol, session, Session, systemPreferences, WebFrameMain } from 'electron'; +import { setUNCHostAllowlist, toUNCHostAllowlist } from 'vs/base/node/unc'; import { validatedIpcMain } from 'vs/base/parts/ipc/electron-main/ipcMain'; import { hostname, release } from 'os'; import { VSBuffer } from 'vs/base/common/buffer'; @@ -311,6 +312,14 @@ export class CodeApplication extends Disposable { } //#endregion + + //#region UNC Host Allowlist (Windows) + + if (isWindows) { + setUNCHostAllowlist(toUNCHostAllowlist(this.configurationService.getValue('security.allowedUNCHosts'))); + } + + //#endregion } private registerListeners(): void { diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index ecec70749114d..11ce9ef7c040d 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -21,10 +21,12 @@ import { getStdinFilePath, hasStdinWithoutTty, readFromStdin, stdinDataListener import { createWaitMarkerFileSync } from 'vs/platform/environment/node/wait'; import product from 'vs/platform/product/common/product'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; -import { randomPath } from 'vs/base/common/extpath'; +import { isUNC, randomPath } from 'vs/base/common/extpath'; import { Utils } from 'vs/platform/profiling/common/profiling'; import { FileAccess } from 'vs/base/common/network'; import { cwd } from 'vs/base/common/process'; +import { addUNCHostToAllowlist } from 'vs/base/node/unc'; +import { URI } from 'vs/base/common/uri'; function shouldSpawnCliProcess(argv: NativeParsedArgs): boolean { return !!argv['install-source'] @@ -116,6 +118,16 @@ export async function main(argv: string[]): Promise { const source = args._[0]; const target = args._[1]; + // Windows: set the paths as allowed UNC paths given + // they are explicitly provided by the user as arguments + if (isWindows) { + for (const path of [source, target]) { + if (isUNC(path)) { + addUNCHostToAllowlist(URI.file(path).authority); + } + } + } + // Validate if ( !source || !target || source === target || // make sure source and target are provided and are not the same diff --git a/src/vs/platform/files/node/diskFileSystemProvider.ts b/src/vs/platform/files/node/diskFileSystemProvider.ts index d977982c3f3bb..f33f49de5de85 100644 --- a/src/vs/platform/files/node/diskFileSystemProvider.ts +++ b/src/vs/platform/files/node/diskFileSystemProvider.ts @@ -707,6 +707,7 @@ export class DiskFileSystemProvider extends AbstractDiskFileSystemProvider imple return error; // avoid double conversion } + let resultError: Error | string = error; let code: FileSystemProviderErrorCode; switch (error.code) { case 'ENOENT': @@ -725,11 +726,15 @@ export class DiskFileSystemProvider extends AbstractDiskFileSystemProvider imple case 'EACCES': code = FileSystemProviderErrorCode.NoPermissions; break; + case 'ERR_UNC_HOST_NOT_ALLOWED': + resultError = `${error.message}. Please update the 'security.allowedUNCHosts' setting if you want to allow this host.`; + code = FileSystemProviderErrorCode.Unknown; + break; default: code = FileSystemProviderErrorCode.Unknown; } - return createFileSystemProviderError(error, code); + return createFileSystemProviderError(resultError, code); } private async toFileSystemProviderWriteError(resource: URI | undefined, error: NodeJS.ErrnoException): Promise { diff --git a/src/vs/platform/utilityProcess/electron-main/utilityProcess.ts b/src/vs/platform/utilityProcess/electron-main/utilityProcess.ts index 9ae28bdcf5974..11b124f3106d0 100644 --- a/src/vs/platform/utilityProcess/electron-main/utilityProcess.ts +++ b/src/vs/platform/utilityProcess/electron-main/utilityProcess.ts @@ -16,6 +16,8 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { removeDangerousEnvVariables } from 'vs/base/common/processes'; import { deepClone } from 'vs/base/common/objects'; +import { isWindows } from 'vs/base/common/platform'; +import { getUNCHostAllowlist } from 'vs/base/node/unc'; export interface IUtilityProcessConfiguration { @@ -259,6 +261,9 @@ export class UtilityProcess extends Disposable { env['VSCODE_CRASH_REPORTER_SANDBOXED_HINT'] = '1'; // TODO@bpasero remove me once sandbox is final } env['VSCODE_CRASH_REPORTER_PROCESS_TYPE'] = configuration.type; + if (isWindows) { + env['NODE_UNC_HOST_ALLOWLIST'] = getUNCHostAllowlist().join('\\'); + } // Remove any environment variables that are not allowed removeDangerousEnvVariables(env); diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index 5d545bb457c77..b5fd46eb80027 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -3,8 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { app, BrowserWindow, WebContents } from 'electron'; +import { app, BrowserWindow, WebContents, shell } from 'electron'; import { Promises } from 'vs/base/node/pfs'; +import { addUNCHostToAllowlist } from 'vs/base/node/unc'; import { hostname, release } from 'os'; import { coalesce, distinct, firstOrDefault } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; @@ -1013,7 +1014,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic return openable.fileUri; } - private async doResolveFilePath(path: string, options: IPathResolveOptions): Promise | undefined> { + private async doResolveFilePath(path: string, options: IPathResolveOptions, skipHandleUNCError?: boolean): Promise | undefined> { // Extract line/col information from path let lineNumber: number | undefined; @@ -1083,6 +1084,11 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic }; } } catch (error) { + + if (error.code === 'ERR_UNC_HOST_NOT_ALLOWED' && !skipHandleUNCError) { + return this.onUNCHostNotAllowed(path, options); + } + const fileUri = URI.file(path); // since file does not seem to exist anymore, remove from recent @@ -1101,6 +1107,33 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic return undefined; } + private async onUNCHostNotAllowed(path: string, options: IPathResolveOptions): Promise | undefined> { + const uri = URI.file(path); + + const { response } = await this.dialogMainService.showMessageBox({ + type: 'warning', + buttons: [ + localize({ key: 'yes', comment: ['&& denotes a mnemonic'] }, "&&Yes"), + localize({ key: 'no', comment: ['&& denotes a mnemonic'] }, "&&No"), + localize({ key: 'learnMore', comment: ['&& denotes a mnemonic'] }, "&&Learn More"), + ], + message: localize('confirmOpenMessage', "The host '{0}' was not found in the list of allowed hosts. Do you want to open it anyway?", uri.authority), + detail: localize('confirmOpenDetail', "The path '{0}' uses a host that is not allowed. Unless you trust the host, you should press 'No'", getPathLabel(uri, { os: OS, tildify: this.environmentMainService })) + }); + + if (response === 0) { + addUNCHostToAllowlist(uri.authority); + + return this.doResolveFilePath(path, options, true /* do not handle UNC error again */); + } + + if (response === 2) { + shell.openExternal('https://aka.ms/vscode-windows-unc'); + } + + return undefined; + } + private doResolveRemotePath(path: string, options: IPathResolveOptions): IPathToOpen | undefined { const first = path.charCodeAt(0); const remoteAuthority = options.remoteAuthority; diff --git a/src/vs/server/node/remoteExtensionHostAgentCli.ts b/src/vs/server/node/remoteExtensionHostAgentCli.ts index 756aa324d3a33..b9105f8cda2a1 100644 --- a/src/vs/server/node/remoteExtensionHostAgentCli.ts +++ b/src/vs/server/node/remoteExtensionHostAgentCli.ts @@ -49,6 +49,7 @@ import { ExtensionsProfileScannerService } from 'vs/platform/extensionManagement import { LogService } from 'vs/platform/log/common/logService'; import { LoggerService } from 'vs/platform/log/node/loggerService'; import { localize } from 'vs/nls'; +import { setUNCHostAllowlist, toUNCHostAllowlist } from 'vs/base/node/unc'; class CliMain extends Disposable { @@ -66,7 +67,14 @@ class CliMain extends Disposable { async run(): Promise { const instantiationService = await this.initServices(); await instantiationService.invokeFunction(async accessor => { + const configurationService = accessor.get(IConfigurationService); const logService = accessor.get(ILogService); + + // On Windows, configure the UNC allow list based on settings + if (process.platform === 'win32') { + setUNCHostAllowlist(toUNCHostAllowlist(configurationService.getValue('security.allowedUNCHosts'))); + } + try { await this.doRun(instantiationService.createInstance(ExtensionManagementCLI, new ConsoleLogger(logService.getLevel(), false))); } catch (error) { diff --git a/src/vs/server/node/remoteExtensionHostAgentServer.ts b/src/vs/server/node/remoteExtensionHostAgentServer.ts index f97d796b770d6..01c46649d690f 100644 --- a/src/vs/server/node/remoteExtensionHostAgentServer.ts +++ b/src/vs/server/node/remoteExtensionHostAgentServer.ts @@ -23,8 +23,10 @@ import { createRegExp, escapeRegExpCharacters } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { findFreePort } from 'vs/base/node/ports'; +import { setUNCHostAllowlist, toUNCHostAllowlist } from 'vs/base/node/unc'; import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -712,6 +714,15 @@ export async function createServer(address: string | net.AddressInfo | null, arg initUnexpectedErrorHandler((error: any) => logService.error(error)); }); + // On Windows, configure the UNC allow list based on settings + instantiationService.invokeFunction((accessor) => { + const configurationService = accessor.get(IConfigurationService); + + if (process.platform === 'win32') { + setUNCHostAllowlist(toUNCHostAllowlist(configurationService.getValue('security.allowedUNCHosts'))); + } + }); + // // On Windows, exit early with warning message to users about potential security issue // if there is node_modules folder under home drive or Users folder. diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 843dcc35f7778..122cdf390be44 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -7,7 +7,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { localize } from 'vs/nls'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common/platform'; -import { ConfigurationMigrationWorkbenchContribution, workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; +import { ConfigurationMigrationWorkbenchContribution, securityConfigurationNodeBase, workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; import { isStandalone } from 'vs/base/browser/browser'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -680,4 +680,21 @@ const registry = Registry.as(ConfigurationExtensions.Con } } }); + + // Security + registry.registerConfiguration({ + ...securityConfigurationNodeBase, + 'properties': { + 'security.allowedUNCHosts': { + 'type': 'array', + 'items': { + 'type': 'string' + }, + 'default': [], + 'markdownDescription': localize('security.allowedUNCHosts', 'A set of UNC host names to allow without user confirmation. If a UNC host is being accessed that is not allowed via this setting or has not been acknowledged via user confirmation, an error will occur and the operation stopped. A restart is required when changing this setting. Find out more about this setting at https://aka.ms/vscode-windows-unc.'), + 'included': isWindows, + 'scope': ConfigurationScope.MACHINE + } + } + }); })(); diff --git a/src/vs/workbench/common/configuration.ts b/src/vs/workbench/common/configuration.ts index ec14cab3484cc..abc42742dd914 100644 --- a/src/vs/workbench/common/configuration.ts +++ b/src/vs/workbench/common/configuration.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; +import { ConfigurationScope, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -26,6 +26,14 @@ export const workbenchConfigurationNodeBase = Object.freeze( 'type': 'object', }); +export const securityConfigurationNodeBase = Object.freeze({ + 'id': 'security', + 'scope': ConfigurationScope.APPLICATION, + 'title': localize('securityConfigurationTitle', "Security"), + 'type': 'object', + 'order': 7 +}); + export const Extensions = { ConfigurationMigration: 'base.contributions.configuration.migration' }; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts b/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts index 8348485db9f6e..f750e05cf9151 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsLayout.ts @@ -254,6 +254,7 @@ export const tocData: ITOCEntry = { { id: 'security', label: localize('security', "Security"), + settings: ['security.*'], children: [ { id: 'security/workspace', diff --git a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts index d4625c6055eaa..ba8a564b65868 100644 --- a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts @@ -25,7 +25,7 @@ interface IConfiguration extends IWindowsConfiguration { update?: { mode?: string }; debug?: { console?: { wordWrap?: boolean } }; editor?: { accessibilitySupport?: 'on' | 'off' | 'auto' }; - security?: { workspace?: { trust?: { enabled?: boolean } } }; + security?: { workspace?: { trust?: { enabled?: boolean } }; allowedUNCHosts?: string[] }; window: IWindowSettings & { experimental?: { windowControlsOverlay?: { enabled?: boolean }; useSandbox?: boolean } }; workbench?: { enableExperiments?: boolean }; _extensionsGallery?: { enablePPE?: boolean }; @@ -44,7 +44,8 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo 'editor.accessibilitySupport', 'security.workspace.trust.enabled', 'workbench.enableExperiments', - '_extensionsGallery.enablePPE' + '_extensionsGallery.enablePPE', + 'security.allowedUNCHosts' ]; private readonly titleBarStyle = new ChangeObserver<'native' | 'custom'>('string'); @@ -58,6 +59,7 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo private readonly workspaceTrustEnabled = new ChangeObserver('boolean'); private readonly experimentsEnabled = new ChangeObserver('boolean'); private readonly enablePPEExtensionsGallery = new ChangeObserver('boolean'); + private readonly allowedUNCHosts = new ChangeObserver('string'); constructor( @IHostService private readonly hostService: IHostService, @@ -117,6 +119,9 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo // Workspace trust processChanged(this.workspaceTrustEnabled.handleChange(config?.security?.workspace?.trust?.enabled)); + + // Allowed UNC Hosts + processChanged(this.allowedUNCHosts.handleChange(config?.security?.allowedUNCHosts?.join('\\'))); } // Experiments diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index 45205704519c0..9709a336f28c8 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -47,6 +47,7 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { MANAGE_TRUST_COMMAND_ID, WorkspaceTrustContext } from 'vs/workbench/contrib/workspace/common/workspace'; import { isWeb } from 'vs/base/common/platform'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { securityConfigurationNodeBase } from 'vs/workbench/common/configuration'; const BANNER_RESTRICTED_MODE = 'workbench.banner.restrictedMode'; const STARTUP_PROMPT_SHOWN_KEY = 'workspace.trust.startupPrompt.shown'; @@ -690,11 +691,7 @@ registerAction2(class extends Action2 { */ Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ - id: 'security', - scope: ConfigurationScope.APPLICATION, - title: localize('securityConfigurationTitle', "Security"), - type: 'object', - order: 7, + ...securityConfigurationNodeBase, properties: { [WORKSPACE_TRUST_ENABLED]: { type: 'boolean',