Skip to content

Commit 2e671b3

Browse files
authored
UNC follow up changes (microsoft#181946)
* settings include update * more cleanup
1 parent a99c29b commit 2e671b3

File tree

9 files changed

+210
-75
lines changed

9 files changed

+210
-75
lines changed

src/main.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const bootstrap = require('./bootstrap');
2222
const bootstrapNode = require('./bootstrap-node');
2323
const { getUserDataPath } = require('./vs/platform/environment/node/userDataPath');
2424
const { stripComments } = require('./vs/base/common/stripComments');
25+
const { getUNCHost, addUNCHostToAllowlist } = require('./vs/base/node/unc');
2526
/** @type {Partial<IProductConfiguration>} */
2627
const product = require('../product.json');
2728
const { app, protocol, crashReporter, Menu } = require('electron');
@@ -35,6 +36,12 @@ bootstrap.enableASARSupport();
3536
// Set userData path before app 'ready' event
3637
const args = parseCLIArgs();
3738
const userDataPath = getUserDataPath(args, product.nameShort ?? 'code-oss-dev');
39+
if (process.platform === 'win32') {
40+
const userDataUNCHost = getUNCHost(userDataPath);
41+
if (userDataUNCHost) {
42+
addUNCHostToAllowlist(userDataUNCHost); // enables to use UNC paths in userDataPath
43+
}
44+
}
3845
app.setPath('userData', userDataPath);
3946

4047
// Resolve code cache path

src/vs/base/node/unc.d.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
/**
7+
* Helper to get the hostname of a possible UNC path.
8+
*/
9+
export function getUNCHost(maybeUNCPath: string | undefined | null): string | undefined;
10+
11+
/**
12+
* Returns the current list of allowed UNC hosts as defined by node.js.
13+
*/
14+
export function getUNCHostAllowlist(): string[];
15+
16+
/**
17+
* Adds one to many UNC host(s) to the allowed list in node.js.
18+
*/
19+
export function addUNCHostToAllowlist(allowedHost: string | string[]): void;

src/vs/base/node/unc.js

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
'use strict';
7+
8+
//@ts-check
9+
10+
(function () {
11+
function factory() {
12+
13+
/**
14+
* @returns {Set<string> | undefined}
15+
*/
16+
function processUNCHostAllowlist() {
17+
18+
// The property `process.uncHostAllowlist` is not available in official node.js
19+
// releases, only in our own builds, so we have to probe for availability
20+
21+
return process.uncHostAllowlist;
22+
}
23+
24+
/**
25+
* @param {unknown} arg0
26+
* @returns {string[]}
27+
*/
28+
function toSafeStringArray(arg0) {
29+
const allowedUNCHosts = new Set();
30+
31+
if (Array.isArray(arg0)) {
32+
for (const host of arg0) {
33+
if (typeof host === 'string') {
34+
allowedUNCHosts.add(host);
35+
}
36+
}
37+
}
38+
39+
return Array.from(allowedUNCHosts);
40+
}
41+
42+
/**
43+
* @returns {string[]}
44+
*/
45+
function getUNCHostAllowlist() {
46+
const allowlist = processUNCHostAllowlist();
47+
if (allowlist) {
48+
return Array.from(allowlist);
49+
}
50+
51+
return [];
52+
}
53+
54+
/**
55+
* @param {string | string[]} allowedHost
56+
*/
57+
function addUNCHostToAllowlist(allowedHost) {
58+
if (process.platform !== 'win32') {
59+
return;
60+
}
61+
62+
const allowlist = processUNCHostAllowlist();
63+
if (allowlist) {
64+
if (typeof allowedHost === 'string') {
65+
allowlist.add(allowedHost);
66+
} else {
67+
for (const host of toSafeStringArray(allowedHost)) {
68+
allowlist.add(host);
69+
}
70+
}
71+
}
72+
}
73+
74+
/**
75+
* @param {string | undefined | null} maybeUNCPath
76+
* @returns {string | undefined}
77+
*/
78+
function getUNCHost(maybeUNCPath) {
79+
if (typeof maybeUNCPath !== 'string') {
80+
return undefined; // require a valid string
81+
}
82+
83+
const uncRoots = [
84+
'\\\\.\\UNC\\', // DOS Device paths (https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats)
85+
'\\\\?\\UNC\\',
86+
'\\\\' // standard UNC path
87+
];
88+
89+
let host = undefined;
90+
91+
for (const uncRoot of uncRoots) {
92+
const indexOfUNCRoot = maybeUNCPath.indexOf(uncRoot);
93+
if (indexOfUNCRoot !== 0) {
94+
continue; // not matching any of our expected UNC roots
95+
}
96+
97+
const indexOfUNCPath = maybeUNCPath.indexOf('\\', uncRoot.length);
98+
if (indexOfUNCPath === -1) {
99+
continue; // no path component found
100+
}
101+
102+
const hostCandidate = maybeUNCPath.substring(uncRoot.length, indexOfUNCPath);
103+
if (hostCandidate) {
104+
host = hostCandidate;
105+
break;
106+
}
107+
}
108+
109+
return host;
110+
}
111+
112+
return {
113+
getUNCHostAllowlist,
114+
addUNCHostToAllowlist,
115+
getUNCHost
116+
};
117+
}
118+
119+
if (typeof define === 'function') {
120+
// amd
121+
define([], function () { return factory(); });
122+
} else if (typeof module === 'object' && typeof module.exports === 'object') {
123+
// commonjs
124+
module.exports = factory();
125+
} else {
126+
console.trace('vs/base/node/unc defined in UNKNOWN context (neither requirejs or commonjs)');
127+
}
128+
})();

src/vs/base/node/unc.ts

Lines changed: 0 additions & 65 deletions
This file was deleted.

src/vs/base/test/node/unc.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { strictEqual } from 'assert';
7+
import { getUNCHost } from 'vs/base/node/unc';
8+
9+
suite('UNC', () => {
10+
11+
test('getUNCHost', () => {
12+
13+
strictEqual(getUNCHost(undefined), undefined);
14+
strictEqual(getUNCHost(null), undefined);
15+
16+
strictEqual(getUNCHost('/'), undefined);
17+
strictEqual(getUNCHost('/foo'), undefined);
18+
19+
strictEqual(getUNCHost('c:'), undefined);
20+
strictEqual(getUNCHost('c:\\'), undefined);
21+
strictEqual(getUNCHost('c:\\foo'), undefined);
22+
strictEqual(getUNCHost('c:\\foo\\\\server\\path'), undefined);
23+
24+
strictEqual(getUNCHost('\\'), undefined);
25+
strictEqual(getUNCHost('\\\\'), undefined);
26+
strictEqual(getUNCHost('\\\\localhost'), undefined);
27+
28+
strictEqual(getUNCHost('\\\\localhost\\'), 'localhost');
29+
strictEqual(getUNCHost('\\\\localhost\\a'), 'localhost');
30+
31+
strictEqual(getUNCHost('\\\\.'), undefined);
32+
strictEqual(getUNCHost('\\\\?'), undefined);
33+
34+
strictEqual(getUNCHost('\\\\.\\localhost'), '.');
35+
strictEqual(getUNCHost('\\\\?\\localhost'), '?');
36+
37+
strictEqual(getUNCHost('\\\\.\\UNC\\localhost'), '.');
38+
strictEqual(getUNCHost('\\\\?\\UNC\\localhost'), '?');
39+
40+
strictEqual(getUNCHost('\\\\.\\UNC\\localhost\\'), 'localhost');
41+
strictEqual(getUNCHost('\\\\?\\UNC\\localhost\\'), 'localhost');
42+
43+
strictEqual(getUNCHost('\\\\.\\UNC\\localhost\\a'), 'localhost');
44+
strictEqual(getUNCHost('\\\\?\\UNC\\localhost\\a'), 'localhost');
45+
});
46+
});

src/vs/code/electron-main/app.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { app, BrowserWindow, dialog, protocol, session, Session, systemPreferences, WebFrameMain } from 'electron';
7-
import { setUNCHostAllowlist, toUNCHostAllowlist } from 'vs/base/node/unc';
7+
import { addUNCHostToAllowlist } from 'vs/base/node/unc';
88
import { validatedIpcMain } from 'vs/base/parts/ipc/electron-main/ipcMain';
99
import { hostname, release } from 'os';
1010
import { VSBuffer } from 'vs/base/common/buffer';
@@ -316,7 +316,7 @@ export class CodeApplication extends Disposable {
316316
//#region UNC Host Allowlist (Windows)
317317

318318
if (isWindows) {
319-
setUNCHostAllowlist(toUNCHostAllowlist(this.configurationService.getValue<unknown>('security.allowedUNCHosts')));
319+
addUNCHostToAllowlist(this.configurationService.getValue('security.allowedUNCHosts'));
320320
}
321321

322322
//#endregion

src/vs/server/node/remoteExtensionHostAgentCli.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import { ExtensionsProfileScannerService } from 'vs/platform/extensionManagement
4949
import { LogService } from 'vs/platform/log/common/logService';
5050
import { LoggerService } from 'vs/platform/log/node/loggerService';
5151
import { localize } from 'vs/nls';
52-
import { setUNCHostAllowlist, toUNCHostAllowlist } from 'vs/base/node/unc';
52+
import { addUNCHostToAllowlist } from 'vs/base/node/unc';
5353

5454
class CliMain extends Disposable {
5555

@@ -71,8 +71,8 @@ class CliMain extends Disposable {
7171
const logService = accessor.get(ILogService);
7272

7373
// On Windows, configure the UNC allow list based on settings
74-
if (process.platform === 'win32') {
75-
setUNCHostAllowlist(toUNCHostAllowlist(configurationService.getValue<unknown>('security.allowedUNCHosts')));
74+
if (isWindows) {
75+
addUNCHostToAllowlist(configurationService.getValue('security.allowedUNCHosts'));
7676
}
7777

7878
try {

src/vs/server/node/remoteExtensionHostAgentServer.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { createRegExp, escapeRegExpCharacters } from 'vs/base/common/strings';
2323
import { URI } from 'vs/base/common/uri';
2424
import { generateUuid } from 'vs/base/common/uuid';
2525
import { findFreePort } from 'vs/base/node/ports';
26-
import { setUNCHostAllowlist, toUNCHostAllowlist } from 'vs/base/node/unc';
26+
import { addUNCHostToAllowlist } from 'vs/base/node/unc';
2727
import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net';
2828
import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
2929
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -718,8 +718,8 @@ export async function createServer(address: string | net.AddressInfo | null, arg
718718
instantiationService.invokeFunction((accessor) => {
719719
const configurationService = accessor.get(IConfigurationService);
720720

721-
if (process.platform === 'win32') {
722-
setUNCHostAllowlist(toUNCHostAllowlist(configurationService.getValue<unknown>('security.allowedUNCHosts')));
721+
if (platform.isWindows) {
722+
addUNCHostToAllowlist(configurationService.getValue('security.allowedUNCHosts'));
723723
}
724724
});
725725

@@ -730,7 +730,7 @@ export async function createServer(address: string | net.AddressInfo | null, arg
730730
instantiationService.invokeFunction((accessor) => {
731731
const logService = accessor.get(ILogService);
732732

733-
if (process.platform === 'win32' && process.env.HOMEDRIVE && process.env.HOMEPATH) {
733+
if (platform.isWindows && process.env.HOMEDRIVE && process.env.HOMEPATH) {
734734
const homeDirModulesPath = join(process.env.HOMEDRIVE, 'node_modules');
735735
const userDir = dirname(join(process.env.HOMEDRIVE, process.env.HOMEPATH));
736736
const userDirModulesPath = join(userDir, 'node_modules');

src/vs/workbench/browser/workbench.contribution.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
697697
},
698698
'default': [],
699699
'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.'),
700-
'included': isWindows,
700+
'included': isWeb ? true /* web maybe connected to a windows machine */ : isWindows,
701701
'scope': ConfigurationScope.MACHINE
702702
}
703703
}

0 commit comments

Comments
 (0)