Remove HttpClient and Proxy agent options completely (#17828)

* change to axios call

* fix lint error

* fix linter

* Remove Http Proxy agent options completely

---------

Co-authored-by: Christopher Suh <chris.s.suh@gmail.com>
This commit is contained in:
Cheena Malhotra 2023-10-24 21:59:51 -07:00 коммит произвёл GitHub
Родитель 6f003d76e1
Коммит 68dbcda9ac
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
12 изменённых файлов: 59 добавлений и 504 удалений

Просмотреть файл

@ -116,8 +116,7 @@
"@azure/msal-common": "^11.0.0",
"@azure/msal-node": "^1.16.0",
"@microsoft/ads-extension-telemetry": "^3.0.2",
"http-proxy-agent": "5.0.0",
"https-proxy-agent": "5.0.0",
"axios": "^0.27.2",
"core-js": "^2.4.1",
"decompress-zip": "^0.2.2",
"ejs": "^3.1.7",

Просмотреть файл

@ -1,343 +0,0 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { INetworkModule, NetworkRequestOptions, NetworkResponse } from '@azure/msal-common';
import * as http from 'http';
import * as https from 'https';
import { constants, HttpMethod, HttpStatus, ProxyStatus } from '../constants';
import { NetworkUtils } from './networkUtils';
/**
* This class implements the API for network requests.
*/
export class HttpClient implements INetworkModule {
private proxyUrl: string;
private customAgentOptions: http.AgentOptions | https.AgentOptions;
constructor(
proxyUrl?: string,
customAgentOptions?: http.AgentOptions | https.AgentOptions
) {
this.proxyUrl = proxyUrl || '';
this.customAgentOptions = customAgentOptions || {};
}
/**
* Http Get request
* @param url
* @param options
*/
async sendGetRequestAsync<T>(
url: string,
options?: NetworkRequestOptions
): Promise<NetworkResponse<T>> {
if (this.proxyUrl) {
return networkRequestViaProxy(url, this.proxyUrl, HttpMethod.GET, options, this.customAgentOptions as http.AgentOptions);
} else {
return networkRequestViaHttps(url, HttpMethod.GET, options, this.customAgentOptions as https.AgentOptions);
}
}
/**
* Http Post request
* @param url
* @param options
*/
async sendPostRequestAsync<T>(
url: string,
options?: NetworkRequestOptions,
cancellationToken?: number
): Promise<NetworkResponse<T>> {
if (this.proxyUrl) {
return networkRequestViaProxy(url, this.proxyUrl, HttpMethod.POST, options, this.customAgentOptions as http.AgentOptions, cancellationToken);
} else {
return networkRequestViaHttps(url, HttpMethod.POST, options, this.customAgentOptions as https.AgentOptions, cancellationToken);
}
}
}
const networkRequestViaProxy = <T>(
destinationUrlString: string,
proxyUrlString: string,
httpMethod: string,
options?: NetworkRequestOptions,
agentOptions?: http.AgentOptions,
timeout?: number
): Promise<NetworkResponse<T>> => {
const destinationUrl = new URL(destinationUrlString);
const proxyUrl = new URL(proxyUrlString);
// 'method: connect' must be used to establish a connection to the proxy
const headers = options?.headers || {} as Record<string, string>;
const tunnelRequestOptions: https.RequestOptions = {
host: proxyUrl.hostname,
port: proxyUrl.port,
method: 'CONNECT',
path: destinationUrl.hostname,
headers: headers
};
if (timeout) {
tunnelRequestOptions.timeout = timeout;
}
if (agentOptions && Object.keys(agentOptions).length) {
tunnelRequestOptions.agent = new http.Agent(agentOptions);
}
// compose a request string for the socket
let postRequestStringContent: string = '';
if (httpMethod === HttpMethod.POST) {
const body = options?.body || '';
postRequestStringContent =
'Content-Type: application/x-www-form-urlencoded\r\n' +
`Content-Length: ${body.length}\r\n` +
`\r\n${body}`;
}
const outgoingRequestString = `${httpMethod.toUpperCase()} ${destinationUrl.href} HTTP/1.1\r\n` +
`Host: ${destinationUrl.host}\r\n` +
'Connection: close\r\n' +
postRequestStringContent +
'\r\n';
return new Promise<NetworkResponse<T>>(((resolve, reject) => {
const request = http.request(tunnelRequestOptions);
if (tunnelRequestOptions.timeout) {
request.on('timeout', () => {
request.destroy();
reject(new Error('Request time out'));
});
}
request.end();
// establish connection to the proxy
request.on('connect', (response, socket) => {
const proxyStatusCode = response?.statusCode || ProxyStatus.SERVER_ERROR;
if ((proxyStatusCode < ProxyStatus.SUCCESS_RANGE_START) || (proxyStatusCode > ProxyStatus.SUCCESS_RANGE_END)) {
request.destroy();
socket.destroy();
reject(new Error(`Error connecting to proxy. Http status code: ${response.statusCode}. Http status message: ${response?.statusMessage || 'Unknown'}`));
}
if (tunnelRequestOptions.timeout) {
// tslint:disable-next-line no-string-based-set-timeout
socket.setTimeout(tunnelRequestOptions.timeout);
socket.on('timeout', () => {
request.destroy();
socket.destroy();
reject(new Error('Request time out'));
});
}
// make a request over an HTTP tunnel
socket.write(outgoingRequestString);
const data: Buffer[] = [];
socket.on('data', (chunk) => {
data.push(chunk);
});
socket.on('end', () => {
// combine all received buffer streams into one buffer, and then into a string
const dataString = Buffer.concat([...data]).toString();
// separate each line into it's own entry in an arry
const dataStringArray = dataString.split('\r\n');
// the first entry will contain the statusCode and statusMessage
const httpStatusCode = parseInt(dataStringArray[0].split(' ')[1], undefined);
// remove 'HTTP/1.1' and the status code to get the status message
const statusMessage = dataStringArray[0].split(' ').slice(2).join(' ');
// the last entry will contain the body
const body = dataStringArray[dataStringArray.length - 1];
// everything in between the first and last entries are the headers
const headersArray = dataStringArray.slice(1, dataStringArray.length - 2);
// build an object out of all the headers
const entries = new Map();
headersArray.forEach((header) => {
/**
* the header might look like 'Content-Length: 1531', but that is just a string
* it needs to be converted to a key/value pair
* split the string at the first instance of ':'
* there may be more than one ':' if the value of the header is supposed to be a JSON object
*/
const headerKeyValue = header.split(new RegExp(/:\s(.*)/s));
const headerKey = headerKeyValue[0];
let headerValue = headerKeyValue[1];
// check if the value of the header is supposed to be a JSON object
try {
const object = JSON.parse(headerValue);
// if it is, then convert it from a string to a JSON object
if (object && (typeof object === 'object')) {
headerValue = object;
}
} catch (e) {
// otherwise, leave it as a string
}
entries.set(headerKey, headerValue);
});
const parsedHeaders = Object.fromEntries(entries) as Record<string, string>;
const networkResponse = NetworkUtils.getNetworkResponse(
parsedHeaders,
parseBody(httpStatusCode, statusMessage, parsedHeaders, body) as T,
httpStatusCode
);
if (((httpStatusCode < HttpStatus.SUCCESS_RANGE_START) || (httpStatusCode > HttpStatus.SUCCESS_RANGE_END)) &&
// do not destroy the request for the device code flow
networkResponse.body['error'] !== constants.AUTHORIZATION_PENDING) {
request.destroy();
}
resolve(networkResponse);
});
socket.on('error', (chunk) => {
request.destroy();
socket.destroy();
reject(new Error(chunk.toString()));
});
});
request.on('error', (chunk) => {
request.destroy();
reject(new Error(chunk.toString()));
});
}));
};
const networkRequestViaHttps = <T>(
urlString: string,
httpMethod: string,
options?: NetworkRequestOptions,
agentOptions?: https.AgentOptions,
timeout?: number
): Promise<NetworkResponse<T>> => {
const isPostRequest = httpMethod === HttpMethod.POST;
const body: string = options?.body || '';
const url = new URL(urlString);
const optionHeaders = options?.headers || {} as Record<string, string>;
let customOptions: https.RequestOptions = {
method: httpMethod,
headers: optionHeaders,
...NetworkUtils.urlToHttpOptions(url)
};
if (timeout) {
customOptions.timeout = timeout;
}
if (agentOptions && Object.keys(agentOptions).length) {
customOptions.agent = new https.Agent(agentOptions);
}
if (isPostRequest) {
// needed for post request to work
customOptions.headers = {
...customOptions.headers,
'Content-Length': body.length
};
}
return new Promise<NetworkResponse<T>>((resolve, reject) => {
const request = https.request(customOptions);
if (timeout) {
request.on('timeout', () => {
request.destroy();
reject(new Error('Request time out'));
});
}
if (isPostRequest) {
request.write(body);
}
request.end();
request.on('response', (response) => {
const headers = response.headers;
const statusCode = response.statusCode as number;
const statusMessage = response.statusMessage;
const data: Buffer[] = [];
response.on('data', (chunk) => {
data.push(chunk);
});
response.on('end', () => {
// combine all received buffer streams into one buffer, and then into a string
const dataBody = Buffer.concat([...data]).toString();
const parsedHeaders = headers as Record<string, string>;
const networkResponse = NetworkUtils.getNetworkResponse(
parsedHeaders,
parseBody(statusCode, statusMessage, parsedHeaders, dataBody) as T,
statusCode
);
if (((statusCode < HttpStatus.SUCCESS_RANGE_START) || (statusCode > HttpStatus.SUCCESS_RANGE_END)) &&
// do not destroy the request for the device code flow
networkResponse.body['error'] !== constants.AUTHORIZATION_PENDING) {
request.destroy();
}
resolve(networkResponse);
});
});
request.on('error', (chunk) => {
request.destroy();
reject(new Error(chunk.toString()));
});
});
};
/**
* Check if extra parsing is needed on the repsonse from the server
* @param statusCode {number} the status code of the response from the server
* @param statusMessage {string | undefined} the status message of the response from the server
* @param headers {Record<string, string>} the headers of the response from the server
* @param body {string} the body from the response of the server
* @returns {Object} JSON parsed body or error object
*/
const parseBody = (statusCode: number, statusMessage: string | undefined, headers: Record<string, string>, body: string) => {
/*
* Informational responses (100 199)
* Successful responses (200 299)
* Redirection messages (300 399)
* Client error responses (400 499)
* Server error responses (500 599)
*/
let parsedBody;
try {
parsedBody = JSON.parse(body);
} catch (error) {
let errorType;
let errorDescriptionHelper;
if ((statusCode >= HttpStatus.CLIENT_ERROR_RANGE_START) && (statusCode <= HttpStatus.CLIENT_ERROR_RANGE_END)) {
errorType = 'client_error';
errorDescriptionHelper = 'A client';
} else if ((statusCode >= HttpStatus.SERVER_ERROR_RANGE_START) && (statusCode <= HttpStatus.SERVER_ERROR_RANGE_END)) {
errorType = 'server_error';
errorDescriptionHelper = 'A server';
} else {
errorType = 'unknown_error';
errorDescriptionHelper = 'An unknown';
}
parsedBody = {
error: errorType,
error_description: `${errorDescriptionHelper} error occured.\nHttp status code: ${statusCode}\nHttp status message: ${statusMessage || 'Unknown'}\nHeaders: ${JSON.stringify(headers)}`
};
}
return parsedBody;
};

Просмотреть файл

@ -15,8 +15,13 @@ import { Logger } from '../../models/logger';
import * as Utils from '../../models/utils';
import { AzureAuthError } from '../azureAuthError';
import * as Constants from '../constants';
import * as azureUtils from '../utils';
import { HttpClient } from './httpClient';
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios';
import { ErrorResponseBody } from '@azure/arm-subscriptions';
export type GetTenantsResponseData = {
value: ITenantResponse[];
};
export type ErrorResponseBodyWithError = Required<ErrorResponseBody>;
// tslint:disable:no-null-keyword
export abstract class MsalAzureAuth {
@ -26,7 +31,6 @@ export abstract class MsalAzureAuth {
protected readonly scopesString: string;
protected readonly clientId: string;
protected readonly resources: Resource[];
protected readonly httpClient: HttpClient;
constructor(
protected readonly providerSettings: IProviderSettings,
@ -41,7 +45,6 @@ export abstract class MsalAzureAuth {
this.clientId = this.providerSettings.clientId;
this.scopes = [...this.providerSettings.scopes];
this.scopesString = this.scopes.join(' ');
this.httpClient = azureUtils.getProxyEnabledHttpClient();
}
public async startLogin(): Promise<IAccount | IPromptFailedResult> {
@ -241,14 +244,9 @@ export abstract class MsalAzureAuth {
try {
this.logger.verbose('Fetching tenants with uri {0}', tenantUri);
let tenantList: string[] = [];
const tenantResponse = await this.httpClient.sendGetRequestAsync<any>(tenantUri, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
});
const data = tenantResponse.body;
if (data.error) {
const tenantResponse = await this.makeGetRequest<GetTenantsResponseData>(tenantUri, token);
const data = tenantResponse.data;
if (this.isErrorResponseBodyWithError(data)) {
this.logger.error(`Error fetching tenants :${data.error.code} - ${data.error.message}`);
throw new Error(`${data.error.code} - ${data.error.message}`);
}
@ -281,6 +279,24 @@ export abstract class MsalAzureAuth {
}
}
private isErrorResponseBodyWithError(body: any): body is ErrorResponseBodyWithError {
return 'error' in body && body.error;
}
private async makeGetRequest<T>(uri: string, token: string): Promise<AxiosResponse<T>> {
const config: AxiosRequestConfig = {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
validateStatus: () => true // Never throw
};
const response: AxiosResponse = await axios.get<T>(uri, config);
this.logger.piiSanitized('GET request ', [{ name: 'response', objOrArray: response.data?.value as ITenantResponse[] ?? response.data as GetTenantsResponseData }], [], uri);
return response;
}
//#region interaction handling
public async handleInteractionRequired(tenant: ITenant, settings: IAADResource, promptUser: boolean = true): Promise<AuthenticationResult | null> {
let shouldOpen: boolean;

Просмотреть файл

@ -12,7 +12,6 @@ import { AzureAuthType, IAADResource, IAccount, IToken } from '../../models/cont
import { AccountStore } from '../accountStore';
import { AzureController } from '../azureController';
import { getAzureActiveDirectoryConfig, getEnableSqlAuthenticationProviderConfig } from '../utils';
import { HttpClient } from './httpClient';
import { MsalAzureAuth } from './msalAzureAuth';
import { MsalAzureCodeGrant } from './msalAzureCodeGrant';
import { MsalAzureDeviceCode } from './msalAzureDeviceCode';
@ -113,7 +112,7 @@ export class MsalAzureController extends AzureController {
public async getAccountSecurityToken(account: IAccount, tenantId: string, settings: IAADResource): Promise<IToken | undefined> {
let azureAuth = await this.getAzureAuthInstance(getAzureActiveDirectoryConfig());
if (azureAuth) {
this.logger.piiSantized(`Getting account security token for ${JSON.stringify(account?.key)} (tenant ${tenantId}). Auth Method = ${AzureAuthType[account?.properties.azureAuthType]}`, [], []);
this.logger.piiSanitized(`Getting account security token for ${JSON.stringify(account?.key)} (tenant ${tenantId}). Auth Method = ${AzureAuthType[account?.properties.azureAuthType]}`, [], []);
tenantId = tenantId || account.properties.owningTenant.id;
let result = await azureAuth.getToken(account, tenantId, settings);
if (!result || !result.account || !result.account.idTokenClaims) {
@ -229,8 +228,7 @@ export class MsalAzureController extends AzureController {
loggerCallback: this.getLoggerCallback(),
logLevel: MsalLogLevel.Trace,
piiLoggingEnabled: true
},
networkClient: new HttpClient()
}
},
cache: {
cachePlugin: this._cachePluginProvider?.getCachePlugin()

Просмотреть файл

@ -7,23 +7,15 @@ import { ResourceManagementClient } from '@azure/arm-resources';
import { SqlManagementClient } from '@azure/arm-sql';
import { SubscriptionClient } from '@azure/arm-subscriptions';
import { PagedAsyncIterableIterator } from '@azure/core-paging';
import { HttpsProxyAgentOptions } from 'https-proxy-agent';
import * as path from 'path';
import * as os from 'os';
import { parse } from 'url';
import * as vscode from 'vscode';
import { getProxyAgentOptions } from '../languageservice/proxy';
import { AzureAuthType, IToken } from '../models/contracts/azure';
import * as Constants from './constants';
import { TokenCredentialWrapper } from './credentialWrapper';
import { HttpClient } from './msal/httpClient';
const configAzureAD = 'azureActiveDirectory';
const configProxy = 'proxy';
const configProxyStrictSSL = 'proxyStrictSSL';
const configProxyAuthorization = 'proxyAuthorization';
/**
* Helper method to convert azure results that comes as pages to an array
* @param pages azure resources as pages
@ -59,9 +51,6 @@ function getConfiguration(): vscode.WorkspaceConfiguration {
return vscode.workspace.getConfiguration(Constants.extensionConfigSectionName);
}
function getHttpConfiguration(): vscode.WorkspaceConfiguration {
return vscode.workspace.getConfiguration(Constants.httpConfigSectionName);
}
export function getAzureActiveDirectoryConfig(): AzureAuthType {
let config = getConfiguration();
if (config) {
@ -96,25 +85,6 @@ export function getEnableConnectionPoolingConfig(): boolean {
return true; // default setting
}
export function getProxyEnabledHttpClient(): HttpClient {
const proxy = <string>getHttpConfiguration().get(configProxy);
const strictSSL = getHttpConfiguration().get(configProxyStrictSSL, true);
const authorization = getHttpConfiguration().get(configProxyAuthorization);
const url = parse(proxy);
let agentOptions = getProxyAgentOptions(url, proxy, strictSSL);
if (authorization && url.protocol === 'https:') {
let httpsAgentOptions = agentOptions as HttpsProxyAgentOptions;
httpsAgentOptions!.headers = Object.assign(httpsAgentOptions!.headers || {}, {
'Proxy-Authorization': authorization
});
agentOptions = httpsAgentOptions;
}
return new HttpClient(proxy, agentOptions);
}
export function getAppDataPath(): string {
let platform = process.platform;
switch (platform) {

Просмотреть файл

@ -9,7 +9,6 @@ import * as https from 'https';
import { parse as parseUrl, Url } from 'url';
import { ILogger } from '../models/interfaces';
import { IHttpClient, IPackage, IStatusView, PackageError } from './interfaces';
import { getProxyAgent, isBoolean } from './proxy';
/*
* Http client class to handle downloading files using http or https urls
@ -23,12 +22,9 @@ export default class HttpClient implements IHttpClient {
urlString: string,
pkg: IPackage,
logger: ILogger,
statusView: IStatusView,
proxy?: string,
strictSSL?: boolean,
authorization?: string): Promise<void> {
statusView: IStatusView): Promise<void> {
const url = parseUrl(urlString);
let options = this.getHttpClientOptions(url, proxy, strictSSL, authorization);
let options = this.getHttpClientOptions(url);
let clientRequest = url.protocol === 'http:' ? http.request : https.request;
return new Promise<void>((resolve, reject) => {
@ -39,7 +35,7 @@ export default class HttpClient implements IHttpClient {
let request = clientRequest(options, response => {
if (response.statusCode === 301 || response.statusCode === 302) {
// Redirect - download from new location
return resolve(this.downloadFile(response.headers.location!, pkg, logger, statusView, proxy, strictSSL, authorization));
return resolve(this.downloadFile(response.headers.location!, pkg, logger, statusView));
}
if (response.statusCode !== 200) {
@ -65,27 +61,22 @@ export default class HttpClient implements IHttpClient {
});
}
private getHttpClientOptions(url: Url, proxy?: string, strictSSL?: boolean, authorization?: string): any {
const agent = getProxyAgent(url, proxy, strictSSL);
private getHttpClientOptions(url: Url): any {
let options: http.RequestOptions = {
host: url.hostname,
path: url.path,
agent: agent
agent: undefined
};
if (url.protocol === 'https:') {
let httpsOptions: https.RequestOptions = {
host: url.hostname,
path: url.path,
agent: agent,
rejectUnauthorized: isBoolean(strictSSL) ? strictSSL : true
agent: undefined,
rejectUnauthorized: true
};
options = httpsOptions;
}
if (authorization) {
options.headers = Object.assign(options.headers || {}, { 'Proxy-Authorization': authorization });
}
return options;
}

Просмотреть файл

@ -48,7 +48,7 @@ export class PackageError extends Error {
}
export interface IHttpClient {
downloadFile(urlString: string, pkg: IPackage, logger: ILogger, statusView: IStatusView, proxy: string, strictSSL: boolean, authorization?: string):
downloadFile(urlString: string, pkg: IPackage, logger: ILogger, statusView: IStatusView):
Promise<void>;
}

Просмотреть файл

@ -1,61 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { HttpProxyAgent, HttpProxyAgentOptions } from 'http-proxy-agent';
import { HttpsProxyAgent, HttpsProxyAgentOptions } from 'https-proxy-agent';
import { parse as parseUrl, Url } from 'url';
function getSystemProxyURL(requestURL: Url): string | undefined {
if (requestURL.protocol === 'http:') {
return process.env.HTTP_PROXY || process.env.http_proxy || undefined;
} else if (requestURL.protocol === 'https:') {
return process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy || undefined;
}
return undefined;
}
export function isBoolean(obj: any): obj is boolean {
return obj === true || obj === false;
}
/*
* Returns the proxy agent using the proxy url in the parameters or the system proxy. Returns null if no proxy found
*/
export function getProxyAgent(requestURL: Url, proxy?: string, strictSSL?: boolean): HttpsProxyAgent | HttpProxyAgent {
const proxyURL = proxy || getSystemProxyURL(requestURL);
if (!proxyURL) {
return undefined;
}
const proxyEndpoint = parseUrl(proxyURL);
const opts = getProxyAgentOptions(requestURL, proxy, strictSSL);
return proxyEndpoint.protocol === 'https:' ? new HttpsProxyAgent(opts as HttpsProxyAgentOptions) : new HttpProxyAgent(opts as HttpProxyAgentOptions);
}
/*
* Returns the proxy agent using the proxy url in the parameters or the system proxy. Returns null if no proxy found
*/
export function getProxyAgentOptions(requestURL: Url, proxy?: string, strictSSL?: boolean): HttpsProxyAgentOptions | HttpProxyAgentOptions {
const proxyURL = proxy || getSystemProxyURL(requestURL);
if (!proxyURL) {
return undefined;
}
const proxyEndpoint = parseUrl(proxyURL);
if (!/^https?:$/.test(proxyEndpoint.protocol!)) {
return undefined;
}
const opts: HttpsProxyAgentOptions | HttpProxyAgentOptions = {
host: proxyEndpoint.hostname,
port: Number(proxyEndpoint.port),
auth: proxyEndpoint.auth,
rejectUnauthorized: isBoolean(strictSSL) ? strictSSL : true
};
return opts;
}

Просмотреть файл

@ -89,10 +89,6 @@ export default class ServiceDownloadProvider {
* Downloads the SQL tools service and decompress it in the install folder.
*/
public async installSQLToolsService(platform: Runtime): Promise<boolean> {
const proxy = <string>this._config.getWorkspaceConfig('http.proxy');
const strictSSL = this._config.getWorkspaceConfig('http.proxyStrictSSL', true);
const authorization = this._config.getWorkspaceConfig('http.proxyAuthorization');
const fileName = this.getDownloadFileName(platform);
const installDirectory = await this.getOrMakeInstallDirectory(platform);
@ -112,7 +108,7 @@ export default class ServiceDownloadProvider {
pkg.tmpFile = tmpResult;
try {
await this._httpClient.downloadFile(pkg.url, pkg, this._logger, this._statusView, proxy, strictSSL, authorization);
await this._httpClient.downloadFile(pkg.url, pkg, this._logger, this._statusView);
this._logger.logDebug(`Downloaded to ${pkg.tmpFile.name}...`);
this._logger.appendLine(' Done!');
await this.install(pkg);
@ -149,6 +145,3 @@ export default class ServiceDownloadProvider {
});
}
}

Просмотреть файл

@ -44,7 +44,7 @@ export class Logger implements ILogger {
* @param stringsToShorten Set of strings to shorten
* @param vals Any other values to add on to the end of the log message
*/
public piiSantized(msg: any, objsToSanitize: { name: string, objOrArray: any | any[] }[],
public piiSanitized(msg: any, objsToSanitize: { name: string, objOrArray: any | any[] }[],
stringsToShorten: { name: string, value: string }[], ...vals: any[]): void {
if (this.piiLogging) {
msg = [

Просмотреть файл

@ -119,9 +119,6 @@ suite('ServiceDownloadProvider Tests', () => {
config.setup(x => x.getSqlToolsConfigValue('downloadFileNames')).returns(() => fileNamesJson);
config.setup(x => x.getSqlToolsServiceDownloadUrl()).returns(() => baseDownloadUrl);
config.setup(x => x.getSqlToolsPackageVersion()).returns(() => version);
config.setup(x => x.getWorkspaceConfig('http.proxy')).returns(() => <any>'proxy');
config.setup(x => x.getWorkspaceConfig('http.proxyStrictSSL', true)).returns(() => <any>true);
config.setup(x => x.getWorkspaceConfig('http.proxyAuthorization')).returns(() => '');
testStatusView.setup(x => x.installingService());
testStatusView.setup(x => x.serviceInstalled());
testLogger.setup(x => x.append(TypeMoq.It.isAny()));
@ -129,8 +126,7 @@ suite('ServiceDownloadProvider Tests', () => {
testDecompressProvider.setup(x => x.decompress(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
.returns(() => { return fixture.decompressResult; });
testHttpClient.setup(x => x.downloadFile(downloadUrl, TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(),
TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()))
testHttpClient.setup(x => x.downloadFile(downloadUrl, TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()))
.returns(() => { return fixture.downloadResult; });
let downloadProvider = new ServiceDownloadProvider(config.object, testLogger.object, testStatusView.object,
testHttpClient.object, testDecompressProvider.object);
@ -149,8 +145,7 @@ suite('ServiceDownloadProvider Tests', () => {
fixture = await createDownloadProvider(fixture);
return fixture.downloadProvider.installSQLToolsService(Runtime.Windows_64).then(_ => {
testHttpClient.verify(x => x.downloadFile(fixture.downloadUrl, TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(),
TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()),
testHttpClient.verify(x => x.downloadFile(fixture.downloadUrl, TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()),
TypeMoq.Times.once());
testDecompressProvider.verify(x => x.decompress(TypeMoq.It.isAny(), TypeMoq.It.isAny()),
TypeMoq.Times.once());
@ -170,8 +165,7 @@ suite('ServiceDownloadProvider Tests', () => {
fixture = await createDownloadProvider(fixture);
return fixture.downloadProvider.installSQLToolsService(Runtime.Windows_64).catch(_ => {
testHttpClient.verify(x => x.downloadFile(fixture.downloadUrl, TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(),
TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()),
testHttpClient.verify(x => x.downloadFile(fixture.downloadUrl, TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()),
TypeMoq.Times.once());
testDecompressProvider.verify(x => x.decompress(TypeMoq.It.isAny(), TypeMoq.It.isAny()),
TypeMoq.Times.never());
@ -190,8 +184,7 @@ suite('ServiceDownloadProvider Tests', () => {
fixture = await createDownloadProvider(fixture);
return fixture.downloadProvider.installSQLToolsService(Runtime.Windows_64).catch(_ => {
testHttpClient.verify(x => x.downloadFile(fixture.downloadUrl, TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(),
TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()),
testHttpClient.verify(x => x.downloadFile(fixture.downloadUrl, TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()),
TypeMoq.Times.once());
testDecompressProvider.verify(x => x.decompress(TypeMoq.It.isAny(), TypeMoq.It.isAny()),
TypeMoq.Times.once());

Просмотреть файл

@ -266,11 +266,6 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
"@tootallnate/once@2":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
"@types/azdata@^1.44.0":
version "1.44.0"
resolved "https://registry.yarnpkg.com/@types/azdata/-/azdata-1.44.0.tgz#c6bb4baacd1b0f74b46742bffd61ae40e922989d"
@ -747,6 +742,14 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
axios@^0.27.2:
version "0.27.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
dependencies:
follow-redirects "^1.14.9"
form-data "^4.0.0"
babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@ -2183,6 +2186,11 @@ fmerge@1.2.0:
resolved "https://registry.yarnpkg.com/fmerge/-/fmerge-1.2.0.tgz#36e99d2ae255e3ee1af666b4df780553671cf692"
integrity sha1-NumdKuJV4+4a9ma033gFU2cc9pI=
follow-redirects@^1.14.9:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
for-in@^1.0.1, for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@ -2798,15 +2806,6 @@ hosted-git-info@^2.1.4:
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
http-proxy-agent@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43"
integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==
dependencies:
"@tootallnate/once" "2"
agent-base "6"
debug "4"
http-proxy-agent@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
@ -2825,7 +2824,7 @@ http-signature@~1.2.0:
jsprim "^1.2.2"
sshpk "^1.7.0"
https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0:
https-proxy-agent@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==