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,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 = [];