diff --git a/src/typings/https-proxy-agent.d.ts b/src/typings/https-proxy-agent.d.ts index d251b9f3130f906aebfc681053fb0ae15064de51..b4be3e030b58b4b0ac0689c282e8289710a59c0a 100644 --- a/src/typings/https-proxy-agent.d.ts +++ b/src/typings/https-proxy-agent.d.ts @@ -5,8 +5,19 @@ declare module 'https-proxy-agent' { + import * as tls from 'tls'; + + interface IHttpsProxyAgentOptions extends tls.ConnectionOptions { + host: string; + port: number; + secureProxy?: boolean; + secureEndpoint?: boolean; + } + class HttpsProxyAgent { constructor(proxy: string); + constructor(opts: IHttpsProxyAgentOptions); } + export = HttpsProxyAgent; } \ No newline at end of file diff --git a/src/vs/base/node/request.ts b/src/vs/base/node/request.ts index 8852d2c094183698042adaf7347b4168ed63f4df..62402ed0a562df852758bba572c10d0f0ab98584 100644 --- a/src/vs/base/node/request.ts +++ b/src/vs/base/node/request.ts @@ -11,8 +11,6 @@ import http = require('http'); import { Url, parse as parseUrl } from 'url'; import { createWriteStream } from 'fs'; import { assign } from 'vs/base/common/objects'; -import HttpProxyAgent = require('http-proxy-agent'); -import HttpsProxyAgent = require('https-proxy-agent'); export interface IRequestOptions { type?: string; @@ -100,36 +98,4 @@ export function json(opts: IRequestOptions): TPromise { pair.res.on('end', () => c(JSON.parse(buffer.join('')))); pair.res.on('error', e); })); -} - -function getSystemProxyURI(requestURL: Url): string { - if (requestURL.protocol === 'http:') { - return process.env.HTTP_PROXY || process.env.http_proxy || null; - } else if (requestURL.protocol === 'https:') { - return process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy || null; - } - - return null; -} - -export function getProxyAgent(rawRequestURL: string, proxyURL: string): any { - let requestURL = parseUrl(rawRequestURL); - let proxyEndpoint = parseUrl(proxyURL); - - if (!/^https?:$/.test(proxyEndpoint.protocol)) { - return null; - } - - return requestURL.protocol === 'http:' ? new HttpProxyAgent(proxyURL) : new HttpsProxyAgent(proxyURL); -} - -export function getSystemProxyAgent(rawRequestURL: string): any { - let requestURL = parseUrl(rawRequestURL); - let proxyURL = getSystemProxyURI(requestURL); - - if (!proxyURL) { - return null; - } - - return getProxyAgent(rawRequestURL, proxyURL); } \ No newline at end of file diff --git a/src/vs/workbench/electron-main/win32/auto-updater.win32.ts b/src/vs/workbench/electron-main/win32/auto-updater.win32.ts index 00f46eef186cbc049282152a95bd679b0d85423e..29dbffdde97609c1efcc9570b279f738befe2b4f 100644 --- a/src/vs/workbench/electron-main/win32/auto-updater.win32.ts +++ b/src/vs/workbench/electron-main/win32/auto-updater.win32.ts @@ -17,7 +17,8 @@ import {ClientRequest} from 'http'; import {mkdirp} from 'vs/base/node/extfs'; import {isString} from 'vs/base/common/types'; import {Promise, TPromise} from 'vs/base/common/winjs.base'; -import {IRequestOptions, download, json, getProxyAgent, getSystemProxyAgent} from 'vs/base/node/request'; +import {IRequestOptions, download, json } from 'vs/base/node/request'; +import { getProxyAgent } from 'vs/workbench/node/proxy'; import {manager as Settings} from 'vs/workbench/electron-main/settings'; import {manager as Lifecycle} from 'vs/workbench/electron-main/lifecycle'; @@ -53,11 +54,11 @@ export class Win32AutoUpdaterImpl extends events.EventEmitter implements IAutoUp this.emit('checking-for-update'); - const httpProxySettings = Settings.getValue('http.proxy'); - const getAgent = url => httpProxySettings ? getProxyAgent(url, httpProxySettings) : getSystemProxyAgent(url); + const proxyUrl = Settings.getValue('http.proxy'); + const strictSSL = Settings.getValue('http.proxy.strictSSL', true); + const agent = getProxyAgent(this.url, { proxyUrl, strictSSL }); - this.currentRequest = - json({ url: this.url, agent: getAgent(this.url) }) + this.currentRequest = json({ url: this.url, agent }) .then(update => { if (!update || !update.url || !update.version) { this.emit('update-not-available'); @@ -73,9 +74,10 @@ export class Win32AutoUpdaterImpl extends events.EventEmitter implements IAutoUp return TPromise.as(updatePackagePath); } - let downloadPath = `${updatePackagePath}.tmp`; + const downloadPath = `${updatePackagePath}.tmp`; + const agent = getProxyAgent(update.url, { proxyUrl, strictSSL }); - return download(downloadPath, { url: update.url, agent: getAgent(update.url) }) + return download(downloadPath, { url: update.url, agent }) .then(() => pfs.rename(downloadPath, updatePackagePath)) .then(() => updatePackagePath); }); diff --git a/src/vs/workbench/node/proxy.ts b/src/vs/workbench/node/proxy.ts new file mode 100644 index 0000000000000000000000000000000000000000..7d446c9b5ed8e36cac2043e9b69da22846d672ac --- /dev/null +++ b/src/vs/workbench/node/proxy.ts @@ -0,0 +1,58 @@ +import { Url, parse as parseUrl } from 'url'; +import HttpProxyAgent = require('http-proxy-agent'); +import HttpsProxyAgent = require('https-proxy-agent'); + +function getAgent(rawRequestURL: string, proxyURL: string, strictSSL: boolean = true): any { + let requestURL = parseUrl(rawRequestURL); + let proxyEndpoint = parseUrl(proxyURL); + + if (!/^https?:$/.test(proxyEndpoint.protocol)) { + return null; + } + + if (requestURL.protocol === 'http:') { + return new HttpProxyAgent(proxyURL); + } + + return new HttpsProxyAgent({ + host: proxyEndpoint.host, + port: Number(proxyEndpoint.port), + rejectUnauthorized: strictSSL + }); +} + +function getSystemProxyURI(requestURL: Url): string { + if (requestURL.protocol === 'http:') { + return process.env.HTTP_PROXY || process.env.http_proxy || null; + } else if (requestURL.protocol === 'https:') { + return process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy || null; + } + + return null; +} + +function getSystemProxyAgent(rawRequestURL: string): any { + let requestURL = parseUrl(rawRequestURL); + let proxyURL = getSystemProxyURI(requestURL); + + if (!proxyURL) { + return null; + } + + return getAgent(rawRequestURL, proxyURL); +} + +export interface IOptions { + proxyUrl?: string; + strictSSL?: boolean; +} + +export function getProxyAgent(rawRequestURL: string, options: IOptions = {}): any { + console.log(rawRequestURL, options); + + if (!options.proxyUrl) { + return getSystemProxyAgent(rawRequestURL); + } + + return getAgent(rawRequestURL, options.proxyUrl, options.strictSSL); +} \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/node/extensionsService.ts b/src/vs/workbench/parts/extensions/node/extensionsService.ts index ebfc1657ca6054bc0993050c6f236cdfce2469ad..db6a2b660a1c2a9c3239a33350cd346a6dfb41de 100644 --- a/src/vs/workbench/parts/extensions/node/extensionsService.ts +++ b/src/vs/workbench/parts/extensions/node/extensionsService.ts @@ -16,7 +16,8 @@ import { assign } from 'vs/base/common/objects'; import { extract, buffer } from 'vs/base/node/zip'; import { Promise, TPromise } from 'vs/base/common/winjs.base'; import { IExtensionsService, IExtension, IExtensionManifest, IGalleryInformation } from 'vs/workbench/parts/extensions/common/extensions'; -import { download, getProxyAgent, getSystemProxyAgent } from 'vs/base/node/request'; +import { download } from 'vs/base/node/request'; +import { getProxyAgent } from 'vs/workbench/node/proxy'; import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService'; import { Limiter } from 'vs/base/common/async'; import Event, { Emitter } from 'vs/base/common/event'; @@ -121,18 +122,23 @@ export class ExtensionsService implements IExtensionsService { const extensionPath = path.join(this.extensionsPath, `${ extension.publisher }.${ extension.name }`); const manifestPath = path.join(extensionPath, 'package.json'); - return UserSettings.getValue(this.contextService, 'http.proxy').then((httpProxySettings) => { - const getAgent = url => httpProxySettings ? getProxyAgent(url, httpProxySettings) : getSystemProxyAgent(url); - return download(zipPath, { url: url, agent: getAgent(url) }) - .then(() => validate(zipPath, extension)) - .then(manifest => { this._onInstallExtension.fire(manifest); return manifest; }) - .then(manifest => extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }).then(() => manifest)) - .then(manifest => { - manifest = assign({ __metadata: galleryInformation }, manifest); - return pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t')); - }) - .then(() => { this._onDidInstallExtension.fire(extension); return extension; }); - }); + const settings = TPromise.join([ + UserSettings.getValue(this.contextService, 'http.proxy'), + UserSettings.getValue(this.contextService, 'http.proxy.strictSSL') + ]); + + return settings + .then(settings => ({ proxyUrl: settings[0], strictSSL: settings[1] })) + .then(options => getProxyAgent(url, options)) + .then(agent => download(zipPath, { url, agent })) + .then(() => validate(zipPath, extension)) + .then(manifest => { this._onInstallExtension.fire(manifest); return manifest; }) + .then(manifest => extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }).then(() => manifest)) + .then(manifest => { + manifest = assign({ __metadata: galleryInformation }, manifest); + return pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t')); + }) + .then(() => { this._onDidInstallExtension.fire(extension); return extension; }); } private installFromZip(zipPath: string): TPromise { diff --git a/src/vs/workbench/services/request/node/requestService.ts b/src/vs/workbench/services/request/node/requestService.ts index 226b818976d2495eae16b0dce0802865d935da76..26491fd21262c9b658b410daab1431f9ba7bd7e6 100644 --- a/src/vs/workbench/services/request/node/requestService.ts +++ b/src/vs/workbench/services/request/node/requestService.ts @@ -125,6 +125,11 @@ confRegistry.registerConfiguration({ 'http.proxy': { 'type': 'string', 'description': nls.localize('proxy', "The proxy setting to use. If not set will be taken from the http_proxy and https_proxy environment variables") + }, + 'http.proxyStrictSSL': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('strictSSL', "Whether the proxy server certificate should be verified against the list of supplied CAs.") } } }); \ No newline at end of file