From fb1d79215e20765f3862c54df12553358947f233 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 28 Jun 2023 12:31:00 +0200 Subject: [PATCH] dialogs - validate and normalize default path (#186467) * dialogs - validate and normalize default path * address feedback --- .../files/browser/files.contribution.ts | 2 ++ .../browser/abstractFileDialogService.ts | 23 +++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 9d17f6e56ce..4f3d6065173 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -325,6 +325,8 @@ configurationRegistry.registerConfiguration({ }, 'files.dialog.defaultPath': { 'type': 'string', + 'pattern': '^((\\/|\\\\\\\\|[a-zA-Z]:\\\\).*)?$', // slash OR UNC-root OR drive-root OR undefined + 'patternErrorMessage': nls.localize('defaultPathErrorMessage', "Default path for file dialogs must be an absolute path (e.g. C:\\\\myFolder or /myFolder)."), 'description': nls.localize('fileDialogDefaultPath', "Default path for file dialogs, overriding user's home path. Only used in the absence of a context-specific path, such as most recently opened file or folder."), 'scope': ConfigurationScope.MACHINE }, diff --git a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts index a4cd6116d9a..557e05e7adc 100644 --- a/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/abstractFileDialogService.ts @@ -11,6 +11,7 @@ import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { URI } from 'vs/base/common/uri'; import * as resources from 'vs/base/common/resources'; +import * as path from 'vs/base/common/path'; import { IInstantiationService, } from 'vs/platform/instantiation/common/instantiation'; import { ISimpleFileDialog, SimpleFileDialog } from 'vs/workbench/services/dialogs/browser/simpleFileDialog'; import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; @@ -93,17 +94,21 @@ export abstract class AbstractFileDialogService implements IFileDialogService { } async preferredHome(schemeFilter = this.getSchemeFilterForWindow()): Promise { - - // Seek a user-local or user-remote machine-scoped override path string depending on whether caller wants a local or a remote home - const inspectedValue = this.configurationService.inspect('files.dialog.defaultPath'); - const dialogHomePath = schemeFilter === Schemas.file ? inspectedValue.userLocalValue : inspectedValue.userRemoteValue; - const userHomePromise = this.pathService.userHome({ preferLocal: schemeFilter === Schemas.file }); - if (!dialogHomePath) { - return userHomePromise; + const preferLocal = schemeFilter === Schemas.file; + const preferredHomeConfig = this.configurationService.inspect('files.dialog.defaultPath'); + const preferredHomeCandidate = preferLocal ? preferredHomeConfig.userLocalValue : preferredHomeConfig.userRemoteValue; + if (preferredHomeCandidate) { + const pathLib = preferLocal ? path : await this.pathService.path; + if (pathLib.isAbsolute(preferredHomeCandidate)) { + const preferredHomeNormalized = pathLib.normalize(preferredHomeCandidate); + const preferredHome = resources.toLocalResource(await this.pathService.fileURI(preferredHomeNormalized), this.environmentService.remoteAuthority, this.pathService.defaultUriScheme); + if (await this.fileService.exists(preferredHome)) { + return preferredHome; + } + } } - const resource = await this.pathService.fileURI(dialogHomePath); - return resources.toLocalResource(resource, this.environmentService.remoteAuthority, this.pathService.defaultUriScheme); + return this.pathService.userHome({ preferLocal }); } async defaultWorkspacePath(schemeFilter = this.getSchemeFilterForWindow()): Promise {