mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
Load root certificates on Windows (#52880)
This commit is contained in:
parent
d17d223ba6
commit
637eef813b
|
@ -339,6 +339,8 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
|
|||
.pipe(util.cleanNodeModule('node-pty', ['binding.gyp', 'build/**', 'src/**', 'tools/**'], ['build/Release/*.exe', 'build/Release/*.dll', 'build/Release/*.node']))
|
||||
.pipe(util.cleanNodeModule('vscode-nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['build/Release/*.node', '**/*.a']))
|
||||
.pipe(util.cleanNodeModule('vsda', ['binding.gyp', 'README.md', 'build/**', '*.bat', '*.sh', '*.cpp', '*.h'], ['build/Release/vsda.node']))
|
||||
.pipe(util.cleanNodeModule('win-ca-lib', ['**/*'], ['package.json', '**/*.node']))
|
||||
.pipe(util.cleanNodeModule('node-addon-api', ['**/*']))
|
||||
.pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*'], 'app/node_modules.asar'));
|
||||
|
||||
let all = es.merge(
|
||||
|
|
|
@ -146,8 +146,9 @@
|
|||
},
|
||||
"optionalDependencies": {
|
||||
"vscode-windows-registry": "1.0.1",
|
||||
"win-ca-lib": "https://github.com/chrmarti/win-ca/releases/download/v2.4.1-lib-test/win-ca-lib-2.4.1.tgz",
|
||||
"windows-foreground-love": "0.1.0",
|
||||
"windows-mutex": "0.2.1",
|
||||
"windows-process-tree": "0.2.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,11 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration)
|
|||
],
|
||||
default: 'override',
|
||||
description: localize('proxySupport', "Use the proxy support for extensions.")
|
||||
},
|
||||
'http.systemCertificates': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: localize('systemCertificates', "Controls whether CA certificates should be loaded from the OS overriding Node.js' built-in CA certificates. Currently only supported on Windows.")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
|
||||
import * as http from 'http';
|
||||
import * as https from 'https';
|
||||
import * as tls from 'tls';
|
||||
import * as nodeurl from 'url';
|
||||
import * as os from 'os';
|
||||
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
|
@ -118,11 +120,23 @@ function setupProxyResolution(
|
|||
results = [];
|
||||
}
|
||||
|
||||
function resolveProxy(req: http.ClientRequest, opts: http.RequestOptions, url: string, callback: (proxy?: string) => void) {
|
||||
function resolveProxy(flags: { useProxySettings: boolean, useSystemCertificates: boolean }, req: http.ClientRequest, opts: http.RequestOptions, url: string, callback: (proxy?: string) => void) {
|
||||
if (!timeout) {
|
||||
timeout = setTimeout(logEvent, 10 * 60 * 1000);
|
||||
}
|
||||
|
||||
useSystemCertificates(extHostLogService, flags.useSystemCertificates, opts, () => {
|
||||
useProxySettings(flags.useProxySettings, req, opts, url, callback);
|
||||
});
|
||||
}
|
||||
|
||||
function useProxySettings(useProxySettings: boolean, req: http.ClientRequest, opts: http.RequestOptions, url: string, callback: (proxy?: string) => void) {
|
||||
|
||||
if (!useProxySettings) {
|
||||
callback('DIRECT');
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedUrl = nodeurl.parse(url); // Coming from Node's URL, sticking with that.
|
||||
|
||||
const hostname = parsedUrl.hostname;
|
||||
|
@ -254,34 +268,43 @@ function noProxyFromEnv(envValue?: string) {
|
|||
}
|
||||
|
||||
function createPatchedModules(configProvider: ExtHostConfigProvider, resolveProxy: ReturnType<typeof setupProxyResolution>) {
|
||||
const setting = {
|
||||
const proxySetting = {
|
||||
config: configProvider.getConfiguration('http')
|
||||
.get<string>('proxySupport') || 'off'
|
||||
};
|
||||
configProvider.onDidChangeConfiguration(e => {
|
||||
setting.config = configProvider.getConfiguration('http')
|
||||
proxySetting.config = configProvider.getConfiguration('http')
|
||||
.get<string>('proxySupport') || 'off';
|
||||
});
|
||||
const certSetting = {
|
||||
config: !!configProvider.getConfiguration('http')
|
||||
.get<boolean>('systemCertificates')
|
||||
};
|
||||
configProvider.onDidChangeConfiguration(e => {
|
||||
certSetting.config = !!configProvider.getConfiguration('http')
|
||||
.get<string>('systemCertificates');
|
||||
});
|
||||
|
||||
return {
|
||||
http: {
|
||||
off: assign({}, http, patches(http, resolveProxy, { config: 'off' }, true)),
|
||||
on: assign({}, http, patches(http, resolveProxy, { config: 'on' }, true)),
|
||||
override: assign({}, http, patches(http, resolveProxy, { config: 'override' }, true)),
|
||||
onRequest: assign({}, http, patches(http, resolveProxy, setting, true)),
|
||||
default: assign(http, patches(http, resolveProxy, setting, false)) // run last
|
||||
off: assign({}, http, patches(http, resolveProxy, { config: 'off' }, certSetting, true)),
|
||||
on: assign({}, http, patches(http, resolveProxy, { config: 'on' }, certSetting, true)),
|
||||
override: assign({}, http, patches(http, resolveProxy, { config: 'override' }, certSetting, true)),
|
||||
onRequest: assign({}, http, patches(http, resolveProxy, proxySetting, certSetting, true)),
|
||||
default: assign(http, patches(http, resolveProxy, proxySetting, certSetting, false)) // run last
|
||||
},
|
||||
https: {
|
||||
off: assign({}, https, patches(https, resolveProxy, { config: 'off' }, true)),
|
||||
on: assign({}, https, patches(https, resolveProxy, { config: 'on' }, true)),
|
||||
override: assign({}, https, patches(https, resolveProxy, { config: 'override' }, true)),
|
||||
onRequest: assign({}, https, patches(https, resolveProxy, setting, true)),
|
||||
default: assign(https, patches(https, resolveProxy, setting, false)) // run last
|
||||
}
|
||||
off: assign({}, https, patches(https, resolveProxy, { config: 'off' }, certSetting, true)),
|
||||
on: assign({}, https, patches(https, resolveProxy, { config: 'on' }, certSetting, true)),
|
||||
override: assign({}, https, patches(https, resolveProxy, { config: 'override' }, certSetting, true)),
|
||||
onRequest: assign({}, https, patches(https, resolveProxy, proxySetting, certSetting, true)),
|
||||
default: assign(https, patches(https, resolveProxy, proxySetting, certSetting, false)) // run last
|
||||
},
|
||||
tls: assign(tls, tlsPatches(tls))
|
||||
};
|
||||
}
|
||||
|
||||
function patches(originals: typeof http | typeof https, resolveProxy: ReturnType<typeof setupProxyResolution>, setting: { config: string; }, onRequest: boolean) {
|
||||
function patches(originals: typeof http | typeof https, resolveProxy: ReturnType<typeof setupProxyResolution>, proxySetting: { config: string }, certSetting: { config: boolean }, onRequest: boolean) {
|
||||
return {
|
||||
get: patch(originals.get),
|
||||
request: patch(originals.request)
|
||||
|
@ -300,12 +323,15 @@ function patches(originals: typeof http | typeof https, resolveProxy: ReturnType
|
|||
}
|
||||
options = options || {};
|
||||
|
||||
const config = onRequest && ((<any>options)._vscodeProxySupport || /* LS */ (<any>options)._vscodeSystemProxy) || setting.config;
|
||||
if (config === 'off') {
|
||||
if (options.socketPath) {
|
||||
return original.apply(null, arguments as unknown as any[]);
|
||||
}
|
||||
|
||||
if (!options.socketPath && (config === 'override' || config === 'on' && !options.agent) && !(options.agent instanceof ProxyAgent)) {
|
||||
const config = onRequest && ((<any>options)._vscodeProxySupport || /* LS */ (<any>options)._vscodeSystemProxy) || proxySetting.config;
|
||||
const useProxySettings = (config === 'override' || config === 'on' && !options.agent) && !(options.agent instanceof ProxyAgent);
|
||||
const useSystemCertificates = certSetting.config && originals === https && !(options as https.RequestOptions).ca;
|
||||
|
||||
if (useProxySettings || useSystemCertificates) {
|
||||
if (url) {
|
||||
const parsed = typeof url === 'string' ? new nodeurl.URL(url) : url;
|
||||
const urlOptions = {
|
||||
|
@ -322,7 +348,7 @@ function patches(originals: typeof http | typeof https, resolveProxy: ReturnType
|
|||
options = { ...options };
|
||||
}
|
||||
options.agent = new ProxyAgent({
|
||||
resolveProxy,
|
||||
resolveProxy: resolveProxy.bind(undefined, { useProxySettings, useSystemCertificates }),
|
||||
defaultPort: originals === https ? 443 : 80,
|
||||
originalAgent: options.agent
|
||||
});
|
||||
|
@ -335,12 +361,35 @@ function patches(originals: typeof http | typeof https, resolveProxy: ReturnType
|
|||
}
|
||||
}
|
||||
|
||||
function tlsPatches(originals: typeof tls) {
|
||||
return {
|
||||
createSecureContext: patch(originals.createSecureContext)
|
||||
};
|
||||
|
||||
function patch(original: typeof tls.createSecureContext): typeof tls.createSecureContext {
|
||||
return function (details: tls.SecureContextOptions): ReturnType<typeof tls.createSecureContext> {
|
||||
const context = original.apply(null, arguments as unknown as any[]);
|
||||
const cas = (details as any)._vscodeAdditionalCAs;
|
||||
if (cas) {
|
||||
for (const ca of cas) {
|
||||
context.context.addCACert(ca);
|
||||
}
|
||||
}
|
||||
return context;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function configureModuleLoading(extensionService: ExtHostExtensionService, lookup: ReturnType<typeof createPatchedModules>): Promise<void> {
|
||||
return extensionService.getExtensionPathIndex()
|
||||
.then(extensionPaths => {
|
||||
const node_module = <any>require.__$__nodeRequire('module');
|
||||
const original = node_module._load;
|
||||
node_module._load = function load(request: string, parent: any, isMain: any) {
|
||||
if (request === 'tls') {
|
||||
return lookup.tls;
|
||||
}
|
||||
|
||||
if (request !== 'http' && request !== 'https') {
|
||||
return original.apply(this, arguments);
|
||||
}
|
||||
|
@ -353,4 +402,65 @@ function configureModuleLoading(extensionService: ExtHostExtensionService, looku
|
|||
return modules.default;
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function useSystemCertificates(extHostLogService: ExtHostLogService, useSystemCertificates: boolean, opts: http.RequestOptions, callback: () => void) {
|
||||
if (useSystemCertificates) {
|
||||
getCertificates(extHostLogService)
|
||||
.then(cas => {
|
||||
if (cas) {
|
||||
(opts as any)._vscodeAdditionalCAs = cas;
|
||||
}
|
||||
callback();
|
||||
})
|
||||
.catch(err => {
|
||||
extHostLogService.error('ProxyResolver#useSystemCertificates', toErrorMessage(err));
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
let _certificates: Promise<typeof https.globalAgent.options.ca | undefined>;
|
||||
async function getCertificates(extHostLogService: ExtHostLogService) {
|
||||
if (!_certificates) {
|
||||
_certificates = readCertificates()
|
||||
.catch(err => {
|
||||
extHostLogService.error('ProxyResolver#getCertificates', toErrorMessage(err));
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
return _certificates;
|
||||
}
|
||||
|
||||
async function readCertificates() {
|
||||
if (process.platform === 'win32') {
|
||||
const winCA = require.__$__nodeRequire<any>('win-ca-lib');
|
||||
|
||||
let ders = [];
|
||||
const store = winCA();
|
||||
try {
|
||||
let der;
|
||||
while (der = store.next()) {
|
||||
ders.push(der);
|
||||
}
|
||||
} finally {
|
||||
store.done();
|
||||
}
|
||||
|
||||
const seen = {};
|
||||
return ders.map(derToPem)
|
||||
.filter(pem => !seen[pem] && (seen[pem] = true));
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function derToPem(blob) {
|
||||
const lines = ['-----BEGIN CERTIFICATE-----'];
|
||||
const der = blob.toString('base64');
|
||||
for (let i = 0; i < der.length; i += 64) {
|
||||
lines.push(der.substr(i, 64));
|
||||
}
|
||||
lines.push('-----END CERTIFICATE-----', '');
|
||||
return lines.join(os.EOL);
|
||||
}
|
||||
|
|
11
yarn.lock
11
yarn.lock
|
@ -5940,6 +5940,11 @@ node-abi@^2.2.0:
|
|||
dependencies:
|
||||
semver "^5.4.1"
|
||||
|
||||
node-addon-api@^1.3.0:
|
||||
version "1.6.2"
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.6.2.tgz#d8aad9781a5cfc4132cc2fecdbdd982534265217"
|
||||
integrity sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA==
|
||||
|
||||
node-libs-browser@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df"
|
||||
|
@ -9585,6 +9590,12 @@ wide-align@^1.1.0:
|
|||
dependencies:
|
||||
string-width "^1.0.2 || 2"
|
||||
|
||||
"win-ca-lib@https://github.com/chrmarti/win-ca/releases/download/v2.4.1-lib-test/win-ca-lib-2.4.1.tgz":
|
||||
version "2.4.1"
|
||||
resolved "https://github.com/chrmarti/win-ca/releases/download/v2.4.1-lib-test/win-ca-lib-2.4.1.tgz#92415b2c45d08b72217011db8050f8c957e208c4"
|
||||
dependencies:
|
||||
node-addon-api "^1.3.0"
|
||||
|
||||
window-size@0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
|
||||
|
|
Loading…
Reference in a new issue