test
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
mol
2024-07-06 22:23:31 +08:00
parent 08173d8497
commit 263cb5ef03
1663 changed files with 526884 additions and 0 deletions

View File

@ -0,0 +1,24 @@
MIT License
Copyright (c) 2014 Nathan Rajlich <nathan@tootallnate.net>
Copyright (c) 2015 Félicien François <felicien@tweakstyle.com>
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,41 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.8 BLOCK -->
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
<!-- END MICROSOFT SECURITY.MD BLOCK -->

View File

@ -0,0 +1,207 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const http_1 = __importDefault(require("http"));
const https_1 = __importDefault(require("https"));
const debug_1 = __importDefault(require("debug"));
const url_1 = require("url");
const http_proxy_agent_1 = require("http-proxy-agent");
const https_proxy_agent_1 = require("https-proxy-agent");
const socks_proxy_agent_1 = require("socks-proxy-agent");
const agent_base_1 = require("agent-base");
const events_1 = __importDefault(require("events"));
const debug = (0, debug_1.default)('pac-proxy-agent');
/**
* The `PacProxyAgent` class.
*
* A few different "protocol" modes are supported (supported protocols are
* backed by the `get-uri` module):
*
* - "pac+data", "data" - refers to an embedded "data:" URI
* - "pac+file", "file" - refers to a local file
* - "pac+ftp", "ftp" - refers to a file located on an FTP server
* - "pac+http", "http" - refers to an HTTP endpoint
* - "pac+https", "https" - refers to an HTTPS endpoint
*
* @api public
*/
class _PacProxyAgent extends agent_base_1.Agent {
constructor(resolver, opts = {}) {
super(opts);
debug('Creating PacProxyAgent with options %o', opts);
this.resolver = resolver;
this.opts = Object.assign({}, opts);
this.cache = undefined;
}
/**
* Called when the node-core HTTP client library is creating a new HTTP request.
*
* @api protected
*/
connect(req, opts) {
return __awaiter(this, void 0, void 0, function* () {
const { secureEndpoint } = opts;
// Calculate the `url` parameter
const defaultPort = secureEndpoint ? 443 : 80;
let path = req.path;
let search = null;
const firstQuestion = path.indexOf('?');
if (firstQuestion !== -1) {
search = path.substring(firstQuestion);
path = path.substring(0, firstQuestion);
}
const urlOpts = Object.assign(Object.assign({}, opts), { protocol: secureEndpoint ? 'https:' : 'http:', pathname: path, search,
// need to use `hostname` instead of `host` otherwise `port` is ignored
hostname: opts.host, host: null, href: null,
// set `port` to null when it is the protocol default port (80 / 443)
port: defaultPort === opts.port ? null : opts.port });
const url = (0, url_1.format)(urlOpts);
debug('url: %o', url);
let result = yield this.resolver(req, opts, url);
// Default to "DIRECT" if a falsey value was returned (or nothing)
if (!result) {
result = 'DIRECT';
}
const proxies = String(result)
.trim()
.split(/\s*;\s*/g)
.filter(Boolean);
if (this.opts.fallbackToDirect && !proxies.includes('DIRECT')) {
proxies.push('DIRECT');
}
for (const proxy of proxies) {
let agent = null;
const [type, target] = proxy.split(/\s+/);
debug('Attempting to use proxy: %o', proxy);
if (type === 'DIRECT') {
// Needed for SNI.
const originalAgent = this.opts.originalAgent;
const defaultAgent = secureEndpoint ? https_1.default.globalAgent : http_1.default.globalAgent;
agent = originalAgent === false ? new defaultAgent.constructor() : (originalAgent || defaultAgent);
}
else if (type === 'SOCKS' || type === 'SOCKS5') {
// Use a SOCKSv5h proxy
agent = new socks_proxy_agent_1.SocksProxyAgent(`socks://${target}`);
}
else if (type === 'SOCKS4') {
// Use a SOCKSv4a proxy
agent = new socks_proxy_agent_1.SocksProxyAgent(`socks4a://${target}`);
}
else if (type === 'PROXY' ||
type === 'HTTP' ||
type === 'HTTPS') {
// Use an HTTP or HTTPS proxy
// http://dev.chromium.org/developers/design-documents/secure-web-proxy
const proxyURL = `${type === 'HTTPS' ? 'https' : 'http'}://${target}`;
if (secureEndpoint) {
agent = new HttpsProxyAgent2(proxyURL, this.opts);
}
else {
agent = new http_proxy_agent_1.HttpProxyAgent(proxyURL, this.opts);
}
}
try {
if (agent) {
let s;
if (agent instanceof agent_base_1.Agent) {
s = yield agent.connect(req, opts);
}
else {
s = agent;
}
req.emit('proxy', { proxy, socket: s });
return s;
}
throw new Error(`Could not determine proxy type for: ${proxy}`);
}
catch (err) {
debug('Got error for proxy %o: %o', proxy, err);
req.emit('proxy', { proxy, error: err });
}
}
throw new Error(`Failed to establish a socket connection to proxies: ${JSON.stringify(proxies)}`);
});
}
}
class HttpsProxyAgent2 extends https_proxy_agent_1.HttpsProxyAgent {
constructor(proxy, opts) {
const addHeaders = {};
const origHeaders = opts === null || opts === void 0 ? void 0 : opts.headers;
const agentOpts = Object.assign(Object.assign({}, opts), { headers: () => {
const headers = origHeaders
? typeof origHeaders === 'function'
? origHeaders()
: origHeaders
: {};
return Object.assign(Object.assign({}, headers), addHeaders);
} });
super(proxy, agentOpts);
this.addHeaders = addHeaders;
this.lookupProxyAuthorization = opts.lookupProxyAuthorization;
}
connect(req, opts, state = {}) {
const _super = Object.create(null, {
connect: { get: () => super.connect }
});
return __awaiter(this, void 0, void 0, function* () {
const tmpReq = new events_1.default();
let connect;
tmpReq.once('proxyConnect', (_connect) => {
connect = _connect;
});
if (this.lookupProxyAuthorization && !this.addHeaders['Proxy-Authorization']) {
try {
const proxyAuthorization = yield this.lookupProxyAuthorization(this.proxy.href, undefined, state);
if (proxyAuthorization) {
this.addHeaders['Proxy-Authorization'] = proxyAuthorization;
}
}
catch (err) {
req.emit('error', err);
}
}
const s = yield _super.connect.call(this, tmpReq, opts);
const proxyAuthenticate = connect === null || connect === void 0 ? void 0 : connect.headers['proxy-authenticate'];
if (this.lookupProxyAuthorization && (connect === null || connect === void 0 ? void 0 : connect.statusCode) === 407 && proxyAuthenticate) {
try {
const proxyAuthorization = yield this.lookupProxyAuthorization(this.proxy.href, proxyAuthenticate, state);
if (proxyAuthorization) {
this.addHeaders['Proxy-Authorization'] = proxyAuthorization;
tmpReq.removeAllListeners();
s.destroy();
return this.connect(req, opts, state);
}
}
catch (err) {
req.emit('error', err);
}
}
req.once('socket', s => tmpReq.emit('socket', s));
return s;
});
}
}
function createPacProxyAgent(resolver, opts) {
if (!opts) {
opts = {};
}
if (typeof resolver !== 'function') {
throw new TypeError('a resolve function must be specified!');
}
return new _PacProxyAgent(resolver, opts);
}
(function (createPacProxyAgent) {
createPacProxyAgent.PacProxyAgent = _PacProxyAgent;
createPacProxyAgent.prototype = _PacProxyAgent.prototype;
})(createPacProxyAgent || (createPacProxyAgent = {}));
module.exports = createPacProxyAgent;

View File

@ -0,0 +1,662 @@
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Nathan Rajlich, Félicien François, Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.testCertificates = exports.toLogString = exports.resetCaches = exports.loadSystemCertificates = exports.createTlsPatch = exports.createNetPatch = exports.createHttpPatch = exports.createProxyResolver = exports.LogLevel = void 0;
const net = __importStar(require("net"));
const tls = __importStar(require("tls"));
const nodeurl = __importStar(require("url"));
const os = __importStar(require("os"));
const fs = __importStar(require("fs"));
const cp = __importStar(require("child_process"));
const crypto = __importStar(require("crypto"));
const agent_1 = __importStar(require("./agent"));
var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["Trace"] = 0] = "Trace";
LogLevel[LogLevel["Debug"] = 1] = "Debug";
LogLevel[LogLevel["Info"] = 2] = "Info";
LogLevel[LogLevel["Warning"] = 3] = "Warning";
LogLevel[LogLevel["Error"] = 4] = "Error";
LogLevel[LogLevel["Critical"] = 5] = "Critical";
LogLevel[LogLevel["Off"] = 6] = "Off";
})(LogLevel || (exports.LogLevel = LogLevel = {}));
const maxCacheEntries = 5000; // Cache can grow twice that much due to 'oldCache'.
function createProxyResolver(params) {
const { getProxyURL, log, getLogLevel, proxyResolveTelemetry: proxyResolverTelemetry, useHostProxy, env } = params;
let envProxy = proxyFromConfigURL(env.https_proxy || env.HTTPS_PROXY || env.http_proxy || env.HTTP_PROXY); // Not standardized.
let envNoProxy = noProxyFromEnv(env.no_proxy || env.NO_PROXY); // Not standardized.
let cacheRolls = 0;
let oldCache = new Map();
let cache = new Map();
function getCacheKey(url) {
// Expecting proxies to usually be the same per scheme://host:port. Assuming that for performance.
return nodeurl.format(Object.assign(Object.assign({}, url), { pathname: undefined, search: undefined, hash: undefined }));
}
function getCachedProxy(key) {
let proxy = cache.get(key);
if (proxy) {
return proxy;
}
proxy = oldCache.get(key);
if (proxy) {
oldCache.delete(key);
cacheProxy(key, proxy);
}
return proxy;
}
function cacheProxy(key, proxy) {
cache.set(key, proxy);
if (cache.size >= maxCacheEntries) {
oldCache = cache;
cache = new Map();
cacheRolls++;
log.debug('ProxyResolver#cacheProxy cacheRolls', cacheRolls);
}
}
let timeout;
let count = 0;
let duration = 0;
let errorCount = 0;
let cacheCount = 0;
let envCount = 0;
let settingsCount = 0;
let localhostCount = 0;
let envNoProxyCount = 0;
let configNoProxyCount = 0;
let results = [];
function logEvent() {
timeout = undefined;
proxyResolverTelemetry({ count, duration, errorCount, cacheCount, cacheSize: cache.size, cacheRolls, envCount, settingsCount, localhostCount, envNoProxyCount, configNoProxyCount, results });
count = duration = errorCount = cacheCount = envCount = settingsCount = localhostCount = envNoProxyCount = configNoProxyCount = 0;
results = [];
}
function resolveProxy(flags, req, opts, url, callback) {
if (!timeout) {
timeout = setTimeout(logEvent, 10 * 60 * 1000);
}
const stackText = ''; // getLogLevel() === LogLevel.Trace ? '\n' + new Error('Error for stack trace').stack : '';
addCertificatesV1(params, flags.addCertificatesV1, opts, () => {
useProxySettings(useHostProxy, flags.useProxySettings, req, opts, url, stackText, callback);
});
}
function useProxySettings(useHostProxy, useProxySettings, req, opts, url, stackText, callback) {
if (!useProxySettings) {
callback('DIRECT');
return;
}
const parsedUrl = nodeurl.parse(url); // Coming from Node's URL, sticking with that.
const hostname = parsedUrl.hostname;
if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1' || hostname === '::ffff:127.0.0.1') {
localhostCount++;
callback('DIRECT');
log.debug('ProxyResolver#resolveProxy localhost', url, 'DIRECT', stackText);
return;
}
const { secureEndpoint } = opts;
const defaultPort = secureEndpoint ? 443 : 80;
// if there are any config entries present then env variables are ignored
let noProxyConfig = params.getNoProxyConfig ? params.getNoProxyConfig() : [];
if (noProxyConfig.length) {
let configNoProxy = noProxyFromConfig(noProxyConfig); // Not standardized.
if (typeof hostname === 'string' && configNoProxy(hostname, String(parsedUrl.port || defaultPort))) {
configNoProxyCount++;
callback('DIRECT');
log.debug('ProxyResolver#resolveProxy configNoProxy', url, 'DIRECT', stackText);
return;
}
}
else {
if (typeof hostname === 'string' && envNoProxy(hostname, String(parsedUrl.port || defaultPort))) {
envNoProxyCount++;
callback('DIRECT');
log.debug('ProxyResolver#resolveProxy envNoProxy', url, 'DIRECT', stackText);
return;
}
}
let settingsProxy = proxyFromConfigURL(getProxyURL());
if (settingsProxy) {
settingsCount++;
callback(settingsProxy);
log.debug('ProxyResolver#resolveProxy settings', url, settingsProxy, stackText);
return;
}
if (envProxy) {
envCount++;
callback(envProxy);
log.debug('ProxyResolver#resolveProxy env', url, envProxy, stackText);
return;
}
const key = getCacheKey(parsedUrl);
const proxy = getCachedProxy(key);
if (proxy) {
cacheCount++;
collectResult(results, proxy, parsedUrl.protocol === 'https:' ? 'HTTPS' : 'HTTP', req);
callback(proxy);
log.debug('ProxyResolver#resolveProxy cached', url, proxy, stackText);
return;
}
if (!useHostProxy) {
callback('DIRECT');
log.debug('ProxyResolver#resolveProxy unconfigured', url, 'DIRECT', stackText);
return;
}
const start = Date.now();
params.resolveProxy(url) // Use full URL to ensure it is an actually used one.
.then(proxy => {
if (proxy) {
cacheProxy(key, proxy);
collectResult(results, proxy, parsedUrl.protocol === 'https:' ? 'HTTPS' : 'HTTP', req);
}
callback(proxy);
log.debug('ProxyResolver#resolveProxy', url, proxy, stackText);
}).then(() => {
count++;
duration = Date.now() - start + duration;
}, err => {
errorCount++;
const fallback = cache.values().next().value; // fall back to any proxy (https://github.com/microsoft/vscode/issues/122825)
callback(fallback);
log.error('ProxyResolver#resolveProxy', fallback, toErrorMessage(err), stackText);
});
}
return resolveProxy;
}
exports.createProxyResolver = createProxyResolver;
function collectResult(results, resolveProxy, connection, req) {
const proxy = resolveProxy ? String(resolveProxy).trim().split(/\s+/, 1)[0] : 'EMPTY';
req.on('response', res => {
const code = `HTTP_${res.statusCode}`;
const result = findOrCreateResult(results, proxy, connection, code);
result.count++;
});
req.on('error', err => {
const code = err && typeof err.code === 'string' && err.code || 'UNKNOWN_ERROR';
const result = findOrCreateResult(results, proxy, connection, code);
result.count++;
});
}
function findOrCreateResult(results, proxy, connection, code) {
for (const result of results) {
if (result.proxy === proxy && result.connection === connection && result.code === code) {
return result;
}
}
const result = { proxy, connection, code, count: 0 };
results.push(result);
return result;
}
function proxyFromConfigURL(configURL) {
if (!configURL) {
return undefined;
}
const url = (configURL || '').trim();
const i = url.indexOf('://');
if (i === -1) {
return undefined;
}
const scheme = url.substr(0, i).toLowerCase();
const proxy = url.substr(i + 3);
if (scheme === 'http') {
return 'PROXY ' + proxy;
}
else if (scheme === 'https') {
return 'HTTPS ' + proxy;
}
else if (scheme === 'socks' || scheme === 'socks5' || scheme === 'socks5h') {
return 'SOCKS ' + proxy;
}
else if (scheme === 'socks4' || scheme === 'socks4a') {
return 'SOCKS4 ' + proxy;
}
return undefined;
}
function shouldBypassProxy(value) {
if (value.includes("*")) {
return () => true;
}
const filters = value
.map(s => s.trim().split(':', 2))
.map(([name, port]) => ({ name, port }))
.filter(filter => !!filter.name)
.map(({ name, port }) => {
const domain = name[0] === '.' ? name : `.${name}`;
return { domain, port };
});
if (!filters.length) {
return () => false;
}
return (hostname, port) => filters.some(({ domain, port: filterPort }) => {
return `.${hostname.toLowerCase()}`.endsWith(domain) && (!filterPort || port === filterPort);
});
}
function noProxyFromEnv(envValue) {
const value = (envValue || '')
.trim()
.toLowerCase()
.split(',');
return shouldBypassProxy(value);
}
function noProxyFromConfig(noProxy) {
const value = noProxy
.map((item) => item.trim().toLowerCase());
return shouldBypassProxy(value);
}
function createHttpPatch(params, originals, resolveProxy) {
return {
get: patch(originals.get),
request: patch(originals.request)
};
function patch(original) {
function patched(url, options, callback) {
if (typeof url !== 'string' && !(url && url.searchParams)) {
callback = options;
options = url;
url = null;
}
if (typeof options === 'function') {
callback = options;
options = null;
}
options = options || {};
if (options.socketPath) {
return original.apply(null, arguments);
}
const originalAgent = options.agent;
if (originalAgent === true) {
throw new Error('Unexpected agent option: true');
}
const isHttps = originals.globalAgent.protocol === 'https:';
const optionsPatched = originalAgent instanceof agent_1.PacProxyAgent;
const config = params.getProxySupport();
const useProxySettings = !optionsPatched && (config === 'override' || config === 'fallback' || (config === 'on' && originalAgent === undefined));
const addCertificatesV1 = !optionsPatched && params.addCertificatesV1() && isHttps && !options.ca;
if (useProxySettings || addCertificatesV1) {
if (url) {
const parsed = typeof url === 'string' ? new nodeurl.URL(url) : url;
const urlOptions = {
protocol: parsed.protocol,
hostname: parsed.hostname.lastIndexOf('[', 0) === 0 ? parsed.hostname.slice(1, -1) : parsed.hostname,
port: parsed.port,
path: `${parsed.pathname}${parsed.search}`
};
if (parsed.username || parsed.password) {
options.auth = `${parsed.username}:${parsed.password}`;
}
options = Object.assign(Object.assign({}, urlOptions), options);
}
else {
options = Object.assign({}, options);
}
const resolveP = (req, opts, url) => new Promise(resolve => resolveProxy({ useProxySettings, addCertificatesV1 }, req, opts, url, resolve));
const host = options.hostname || options.host;
const isLocalhost = !host || host === 'localhost' || host === '127.0.0.1'; // Avoiding https://github.com/microsoft/vscode/issues/120354
options.agent = (0, agent_1.default)(resolveP, {
originalAgent: (!useProxySettings || isLocalhost || config === 'fallback') ? originalAgent : undefined,
lookupProxyAuthorization: params.lookupProxyAuthorization,
});
return original(options, callback);
}
return original.apply(null, arguments);
}
return patched;
}
}
exports.createHttpPatch = createHttpPatch;
function createNetPatch(params, originals) {
return {
connect: patchNetConnect(params, originals.connect),
};
}
exports.createNetPatch = createNetPatch;
function patchNetConnect(params, original) {
function connect(...args) {
if (params.getLogLevel() === LogLevel.Trace) {
params.log.trace('ProxyResolver#net.connect', toLogString(args));
}
if (!params.addCertificatesV2()) {
return original.apply(null, arguments);
}
const socket = new net.Socket();
socket.connecting = true;
getOrLoadAdditionalCertificates(params)
.then(() => {
const options = args.find(arg => arg && typeof arg === 'object');
if (options === null || options === void 0 ? void 0 : options.timeout) {
socket.setTimeout(options.timeout);
}
socket.connect.apply(socket, arguments);
})
.catch(err => {
params.log.error('ProxyResolver#net.connect', toErrorMessage(err));
});
return socket;
}
return connect;
}
function createTlsPatch(params, originals) {
return {
connect: patchTlsConnect(params, originals.connect),
createSecureContext: patchCreateSecureContext(originals.createSecureContext),
};
}
exports.createTlsPatch = createTlsPatch;
function patchTlsConnect(params, original) {
function connect(...args) {
if (params.getLogLevel() === LogLevel.Trace) {
params.log.trace('ProxyResolver#tls.connect', toLogString(args));
}
let options = args.find(arg => arg && typeof arg === 'object');
if (!params.addCertificatesV2() || (options === null || options === void 0 ? void 0 : options.ca)) {
return original.apply(null, arguments);
}
let secureConnectListener = args.find(arg => typeof arg === 'function');
if (!options) {
options = {};
const listenerIndex = args.findIndex(arg => typeof arg === 'function');
if (listenerIndex !== -1) {
args[listenerIndex - 1] = options;
}
else {
args[2] = options;
}
}
else {
options = Object.assign({}, options);
}
const port = typeof args[0] === 'number' ? args[0]
: typeof args[0] === 'string' && !isNaN(Number(args[0])) ? Number(args[0]) // E.g., http2 module passes port as string.
: options.port;
const host = typeof args[1] === 'string' ? args[1] : options.host;
let tlsSocket;
if (options.socket) {
if (!options.secureContext) {
options.secureContext = tls.createSecureContext(options);
}
if (!_certificates) {
params.log.trace('ProxyResolver#tls.connect waiting for existing socket connect');
options.socket.once('connect', () => {
params.log.trace('ProxyResolver#tls.connect got existing socket connect - adding certs');
for (const cert of _certificates || []) {
options.secureContext.context.addCACert(cert);
}
});
}
else {
params.log.trace('ProxyResolver#tls.connect existing socket already connected - adding certs');
for (const cert of _certificates) {
options.secureContext.context.addCACert(cert);
}
}
}
else {
if (!options.secureContext) {
options.secureContext = tls.createSecureContext(options);
}
params.log.trace('ProxyResolver#tls.connect creating unconnected socket');
const socket = options.socket = new net.Socket();
socket.connecting = true;
getOrLoadAdditionalCertificates(params)
.then(caCertificates => {
params.log.trace('ProxyResolver#tls.connect adding certs before connecting socket');
for (const cert of caCertificates) {
options.secureContext.context.addCACert(cert);
}
if (options === null || options === void 0 ? void 0 : options.timeout) {
socket.setTimeout(options.timeout);
socket.once('timeout', () => {
tlsSocket.emit('timeout');
});
}
socket.connect(Object.assign({ port: port, host }, options));
})
.catch(err => {
params.log.error('ProxyResolver#tls.connect', toErrorMessage(err));
});
}
if (typeof args[1] === 'string') {
tlsSocket = original(port, host, options, secureConnectListener);
}
else if (typeof args[0] === 'number' || typeof args[0] === 'string' && !isNaN(Number(args[0]))) {
tlsSocket = original(port, options, secureConnectListener);
}
else {
tlsSocket = original(options, secureConnectListener);
}
return tlsSocket;
}
return connect;
}
function patchCreateSecureContext(original) {
return function (details) {
const context = original.apply(null, arguments);
const certs = details === null || details === void 0 ? void 0 : details._vscodeAdditionalCaCerts;
if (certs) {
for (const cert of certs) {
context.context.addCACert(cert);
}
}
return context;
};
}
function addCertificatesV1(params, addCertificatesV1, opts, callback) {
if (addCertificatesV1) {
getOrLoadAdditionalCertificates(params)
.then(caCertificates => {
opts._vscodeAdditionalCaCerts = caCertificates;
callback();
})
.catch(err => {
params.log.error('ProxyResolver#addCertificatesV1', toErrorMessage(err));
});
}
else {
callback();
}
}
let _certificatesPromise;
let _certificates;
function getOrLoadAdditionalCertificates(params) {
return __awaiter(this, void 0, void 0, function* () {
if (!_certificatesPromise) {
_certificatesPromise = (() => __awaiter(this, void 0, void 0, function* () {
return _certificates = yield params.loadAdditionalCertificates();
}))();
}
return _certificatesPromise;
});
}
let _systemCertificatesPromise;
function loadSystemCertificates(params) {
return __awaiter(this, void 0, void 0, function* () {
if (!_systemCertificatesPromise) {
_systemCertificatesPromise = (() => __awaiter(this, void 0, void 0, function* () {
try {
const certs = yield readSystemCertificates();
params.log.debug('ProxyResolver#loadSystemCertificates count', certs.length);
const now = Date.now();
const filtered = certs
.filter(cert => {
try {
const parsedCert = new crypto.X509Certificate(cert);
const parsedDate = Date.parse(parsedCert.validTo);
return isNaN(parsedDate) || parsedDate > now;
}
catch (err) {
params.log.debug('ProxyResolver#loadSystemCertificates parse error', toErrorMessage(err));
return false;
}
});
params.log.debug('ProxyResolver#loadSystemCertificates count filtered', filtered.length);
return filtered;
}
catch (err) {
params.log.error('ProxyResolver#loadSystemCertificates error', toErrorMessage(err));
return [];
}
}))();
}
return _systemCertificatesPromise;
});
}
exports.loadSystemCertificates = loadSystemCertificates;
function resetCaches() {
_certificatesPromise = undefined;
_certificates = undefined;
_systemCertificatesPromise = undefined;
}
exports.resetCaches = resetCaches;
function readSystemCertificates() {
return __awaiter(this, void 0, void 0, function* () {
if (process.platform === 'win32') {
return readWindowsCaCertificates();
}
if (process.platform === 'darwin') {
return readMacCaCertificates();
}
if (process.platform === 'linux') {
return readLinuxCaCertificates();
}
return [];
});
}
function readWindowsCaCertificates() {
return __awaiter(this, void 0, void 0, function* () {
// @ts-ignore Windows only
const winCA = yield Promise.resolve().then(() => __importStar(require('@vscode/windows-ca-certs')));
let ders = [];
const store = new winCA.Crypt32();
try {
let der;
while (der = store.next()) {
ders.push(der);
}
}
finally {
store.done();
}
const certs = new Set(ders.map(derToPem));
return Array.from(certs);
});
}
function readMacCaCertificates() {
return __awaiter(this, void 0, void 0, function* () {
const stdout = yield new Promise((resolve, reject) => {
const child = cp.spawn('/usr/bin/security', ['find-certificate', '-a', '-p']);
const stdout = [];
child.stdout.setEncoding('utf8');
child.stdout.on('data', str => stdout.push(str));
child.on('error', reject);
child.on('exit', code => code ? reject(code) : resolve(stdout.join('')));
});
const certs = new Set(stdout.split(/(?=-----BEGIN CERTIFICATE-----)/g)
.filter(pem => !!pem.length));
return Array.from(certs);
});
}
const linuxCaCertificatePaths = [
'/etc/ssl/certs/ca-certificates.crt',
'/etc/ssl/certs/ca-bundle.crt',
'/etc/ssl/ca-bundle.pem', // OpenSUSE
];
function readLinuxCaCertificates() {
return __awaiter(this, void 0, void 0, function* () {
for (const certPath of linuxCaCertificatePaths) {
try {
const content = yield fs.promises.readFile(certPath, { encoding: 'utf8' });
const certs = new Set(content.split(/(?=-----BEGIN CERTIFICATE-----)/g)
.filter(pem => !!pem.length));
return Array.from(certs);
}
catch (err) {
if ((err === null || err === void 0 ? void 0 : err.code) !== 'ENOENT') {
throw err;
}
}
}
return [];
});
}
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);
}
function toErrorMessage(err) {
return err && (err.stack || err.message) || String(err);
}
function toLogString(args) {
return `[${args.map(arg => JSON.stringify(arg, (key, value) => {
const t = typeof value;
if (t === 'object') {
if (key) {
if ((key === 'ca' || key === '_vscodeAdditionalCaCerts') && Array.isArray(value)) {
return `[${value.length} certs]`;
}
if (key === 'ca' && (typeof value === 'string' || Buffer.isBuffer(value))) {
return `[${(value.toString().match(/-----BEGIN CERTIFICATE-----/g) || []).length} certs]`;
}
return !value || value.toString ? String(value) : Object.prototype.toString.call(value);
}
else {
return value;
}
}
if (t === 'function') {
return `[Function: ${value.name}]`;
}
if (t === 'bigint') {
return String(value);
}
if (t === 'string' && value.length > 25) {
const len = `[${value.length} chars]`;
return `${value.substr(0, 25 - len.length)}${len}`;
}
return value;
})).join(', ')}]`;
}
exports.toLogString = toLogString;
/**
* Certificates for testing. These are not automatically used, but can be added in
* ProxyAgentParams#loadAdditionalCertificates(). This just provides a shared array
* between production code and tests.
*/
exports.testCertificates = [];

View File

@ -0,0 +1,50 @@
{
"name": "@vscode/proxy-agent",
"version": "0.21.0",
"description": "NodeJS http(s) agent implementation for VS Code",
"main": "out/index.js",
"types": "out/index.d.ts",
"repository": {
"type": "git",
"url": "git://github.com/microsoft/vscode-proxy-agent.git"
},
"keywords": [
"proxy",
"agent",
"http",
"https",
"socks",
"request",
"access"
],
"authors": [
"Nathan Rajlich <nathan@tootallnate.net> (http://n8.io/)",
"Félicien François <felicien@tweakstyle.com>",
"Microsoft Corporation"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/microsoft/vscode-proxy-agent/issues"
},
"homepage": "https://github.com/microsoft/vscode-proxy-agent",
"dependencies": {
"@tootallnate/once": "^3.0.0",
"agent-base": "^7.0.1",
"debug": "^4.3.4",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2",
"socks-proxy-agent": "^8.0.1"
},
"devDependencies": {
"@types/debug": "^4.1.9",
"@types/node": "^20.8.4",
"typescript": "^5.2.2"
},
"scripts": {
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./"
},
"optionalDependencies": {
"@vscode/windows-ca-certs": "^0.3.1"
}
}