Merge from vscode 4d91d96e5e121b38d33508cdef17868bab255eae

This commit is contained in:
ADS Merger
2020-06-18 04:32:54 +00:00
committed by AzureDataStudio
parent a971aee5bd
commit 5e7071e466
1002 changed files with 24201 additions and 13193 deletions

View File

@@ -13,7 +13,7 @@ const SecondLevelDomainMatcher = /([^@:.]+\.[^@:.]+)(:\d+)?$/;
const RemoteMatcher = /^\s*url\s*=\s*(.+\S)\s*$/mg;
const AnyButDot = /[^.]/g;
export const SecondLevelDomainWhitelist = [
export const AllowedSecondLevelDomains = [
'github.com',
'bitbucket.org',
'visualstudio.com',
@@ -54,7 +54,7 @@ function extractDomain(url: string): string | null {
return null;
}
export function getDomainsOfRemotes(text: string, whitelist: string[]): string[] {
export function getDomainsOfRemotes(text: string, allowedDomains: readonly string[]): string[] {
const domains = new Set<string>();
let match: RegExpExecArray | null;
while (match = RemoteMatcher.exec(text)) {
@@ -64,16 +64,9 @@ export function getDomainsOfRemotes(text: string, whitelist: string[]): string[]
}
}
const whitemap = whitelist.reduce((map, key) => {
map[key] = true;
return map;
}, Object.create(null));
const elements: string[] = [];
domains.forEach(e => elements.push(e));
return elements
.map(key => whitemap[key] ? key : key.replace(AnyButDot, 'a'));
const allowedDomainsSet = new Set(allowedDomains);
return Array.from(domains)
.map(key => allowedDomainsSet.has(key) ? key : key.replace(AnyButDot, 'a'));
}
function stripPort(authority: string): string | null {

View File

@@ -12,7 +12,7 @@ import { isUndefinedOrNull } from 'vs/base/common/types';
export class GlobalExtensionEnablementService extends Disposable implements IGlobalExtensionEnablementService {
_serviceBrand: undefined;
declare readonly _serviceBrand: undefined;
private _onDidChangeEnablement = new Emitter<{ readonly extensions: IExtensionIdentifier[], readonly source?: string }>();
readonly onDidChangeEnablement: Event<{ readonly extensions: IExtensionIdentifier[], readonly source?: string }> = this._onDidChangeEnablement.event;

View File

@@ -225,7 +225,7 @@ function getCoreTranslationAssets(version: IRawGalleryExtensionVersion): [string
function getRepositoryAsset(version: IRawGalleryExtensionVersion): IGalleryExtensionAsset | null {
if (version.properties) {
const results = version.properties.filter(p => p.key === AssetType.Repository);
const gitRegExp = new RegExp('((git|ssh|http(s)?)|(git@[\w\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)(/)?');
const gitRegExp = new RegExp('((git|ssh|http(s)?)|(git@[\w.]+))(:(//)?)([\w.@\:/\-~]+)(.git)(/)?');
const uri = results.filter(r => gitRegExp.test(r.value))[0];
return uri ? { uri: uri.value, fallbackUri: uri.value } : null;
@@ -371,7 +371,7 @@ interface IRawExtensionsReport {
export class ExtensionGalleryService implements IExtensionGalleryService {
_serviceBrand: undefined;
declare readonly _serviceBrand: undefined;
private extensionsGalleryUrl: string | undefined;
private extensionsControlUrl: string | undefined;

View File

@@ -12,7 +12,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { IExtensionManifest, IExtension, ExtensionType } from 'vs/platform/extensions/common/extensions';
import { IExeBasedExtensionTip } from 'vs/platform/product/common/productService';
export const EXTENSION_IDENTIFIER_PATTERN = '^([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*)$';
export const EXTENSION_IDENTIFIER_PATTERN = '^([a-z0-9A-Z][a-z0-9-A-Z]*)\\.([a-z0-9A-Z][a-z0-9-A-Z]*)$';
export const EXTENSION_IDENTIFIER_REGEX = new RegExp(EXTENSION_IDENTIFIER_PATTERN);
export interface IGalleryExtensionProperties {
@@ -153,7 +153,7 @@ export interface ITranslation {
}
export interface IExtensionGalleryService {
_serviceBrand: undefined;
readonly _serviceBrand: undefined;
isEnabled(): boolean;
query(token: CancellationToken): Promise<IPager<IGalleryExtension>>;
query(options: IQueryOptions, token: CancellationToken): Promise<IPager<IGalleryExtension>>;
@@ -200,7 +200,7 @@ export class ExtensionManagementError extends Error {
}
export interface IExtensionManagementService {
_serviceBrand: undefined;
readonly _serviceBrand: undefined;
onInstallExtension: Event<InstallExtensionEvent>;
onDidInstallExtension: Event<DidInstallExtensionEvent>;
@@ -225,7 +225,7 @@ export const ENABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/enabled';
export const IGlobalExtensionEnablementService = createDecorator<IGlobalExtensionEnablementService>('IGlobalExtensionEnablementService');
export interface IGlobalExtensionEnablementService {
_serviceBrand: undefined;
readonly _serviceBrand: undefined;
readonly onDidChangeEnablement: Event<{ readonly extensions: IExtensionIdentifier[], readonly source?: string }>;
getDisabledExtensions(): IExtensionIdentifier[];
@@ -246,7 +246,7 @@ export type IWorkspaceTips = { readonly remoteSet: string[]; readonly recommenda
export const IExtensionTipsService = createDecorator<IExtensionTipsService>('IExtensionTipsService');
export interface IExtensionTipsService {
_serviceBrand: undefined;
readonly _serviceBrand: undefined;
getConfigBasedTips(folder: URI): Promise<IConfigBasedExtensionTip[]>;
getImportantExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]>;

View File

@@ -77,7 +77,7 @@ export class ExtensionManagementChannel implements IServerChannel {
export class ExtensionManagementChannelClient implements IExtensionManagementService {
_serviceBrand: undefined;
declare readonly _serviceBrand: undefined;
constructor(
private readonly channel: IChannel,

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { tmpdir } from 'os';
import { Disposable } from 'vs/base/common/lifecycle';
import { IFileService, IFileStatWithMetadata } from 'vs/platform/files/common/files';
import { IExtensionGalleryService, IGalleryExtension, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';
@@ -20,9 +19,9 @@ const ExtensionIdVersionRegex = /^([^.]+\..+)-(\d+\.\d+\.\d+)$/;
export class ExtensionsDownloader extends Disposable {
private readonly extensionsDownloadDir: URI = URI.file(tmpdir());
private readonly cache: number = 0;
private readonly cleanUpPromise: Promise<void> = Promise.resolve();
private readonly extensionsDownloadDir: URI;
private readonly cache: number;
private readonly cleanUpPromise: Promise<void>;
constructor(
@IEnvironmentService environmentService: INativeEnvironmentService,
@@ -31,11 +30,9 @@ export class ExtensionsDownloader extends Disposable {
@ILogService private readonly logService: ILogService,
) {
super();
if (environmentService.extensionsDownloadPath) {
this.extensionsDownloadDir = URI.file(environmentService.extensionsDownloadPath);
this.cache = 20; // Cache 20 downloads
this.cleanUpPromise = this.cleanUp();
}
this.extensionsDownloadDir = URI.file(environmentService.extensionsDownloadPath);
this.cache = 20; // Cache 20 downloads
this.cleanUpPromise = this.cleanUp();
}
async downloadExtension(extension: IGalleryExtension, operation: InstallOperation): Promise<URI> {
@@ -46,10 +43,7 @@ export class ExtensionsDownloader extends Disposable {
}
async delete(location: URI): Promise<void> {
// Delete immediately if caching is disabled
if (!this.cache) {
await this.fileService.del(location);
}
// noop as caching is enabled always
}
private async download(extension: IGalleryExtension, location: URI, operation: InstallOperation): Promise<void> {

View File

@@ -61,7 +61,7 @@ interface InstallableExtension {
export class ExtensionManagementService extends Disposable implements IExtensionManagementService {
_serviceBrand: undefined;
declare readonly _serviceBrand: undefined;
private readonly extensionsScanner: ExtensionsScanner;
private reportedExtensions: Promise<IReportedExtension[]> | undefined;
@@ -178,7 +178,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
if (identifierWithVersion.equals(new ExtensionIdentifierWithVersion(existing.identifier, existing.manifest.version))) {
return this.extensionsScanner.removeExtension(existing, 'existing').then(null, e => Promise.reject(new Error(nls.localize('restartCode', "Please restart Azure Data Studio before reinstalling {0}.", manifest.displayName || manifest.name))));
} else if (semver.gt(existing.manifest.version, manifest.version)) {
return this.uninstall(existing, true);
return this.uninstallExtension(existing);
}
} else {
// Remove the extension with same version if it is already uninstalled.
@@ -309,7 +309,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
.then(local => this.extensionsDownloader.delete(URI.file(installableExtension.zipPath)).finally(() => { }).then(() => local));
})
.then(local => this.installDependenciesAndPackExtensions(local, existingExtension)
.then(() => local, error => this.uninstall(local, true).then(() => Promise.reject(error), () => Promise.reject(error))))
.then(() => local, error => this.uninstall(local).then(() => Promise.reject(error), () => Promise.reject(error))))
.then(
async local => {
if (existingExtension && semver.neq(existingExtension.manifest.version, extension.version)) {
@@ -480,11 +480,11 @@ export class ExtensionManagementService extends Disposable implements IExtension
return this.getInstalled(ExtensionType.User)
.then(installed =>
Promise.all(installed.filter(local => extensions.some(galleryExtension => new ExtensionIdentifierWithVersion(local.identifier, local.manifest.version).equals(new ExtensionIdentifierWithVersion(galleryExtension.identifier, galleryExtension.version)))) // Check with version because we want to rollback the exact version
.map(local => this.uninstall(local, true))))
.map(local => this.uninstall(local))))
.then(() => undefined, () => undefined);
}
uninstall(extension: ILocalExtension, force = false): Promise<void> {
uninstall(extension: ILocalExtension): Promise<void> {
this.logService.trace('ExtensionManagementService#uninstall', extension.identifier.id);
return this.toNonCancellablePromise(this.getInstalled(ExtensionType.User)
.then(installed => {

View File

@@ -8,7 +8,7 @@ import { getDomainsOfRemotes, getRemotes } from 'vs/platform/extensionManagement
suite('Config Remotes', () => {
const whitelist = [
const allowedDomains = [
'github.com',
'github2.com',
'github3.com',
@@ -20,37 +20,37 @@ suite('Config Remotes', () => {
];
test('HTTPS remotes', function () {
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://github.com/Microsoft/vscode.git'), whitelist), ['github.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://git.example.com/gitproject.git'), whitelist), ['example.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://username@github2.com/username/repository.git'), whitelist), ['github2.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://username:password@github3.com/username/repository.git'), whitelist), ['github3.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://username:password@example2.com:1234/username/repository.git'), whitelist), ['example2.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://example3.com:1234/username/repository.git'), whitelist), ['example3.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://github.com/Microsoft/vscode.git'), allowedDomains), ['github.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://git.example.com/gitproject.git'), allowedDomains), ['example.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://username@github2.com/username/repository.git'), allowedDomains), ['github2.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://username:password@github3.com/username/repository.git'), allowedDomains), ['github3.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://username:password@example2.com:1234/username/repository.git'), allowedDomains), ['example2.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('https://example3.com:1234/username/repository.git'), allowedDomains), ['example3.com']);
});
test('SSH remotes', function () {
assert.deepStrictEqual(getDomainsOfRemotes(remote('ssh://user@git.server.org/project.git'), whitelist), ['server.org']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('ssh://user@git.server.org/project.git'), allowedDomains), ['server.org']);
});
test('SCP-like remotes', function () {
assert.deepStrictEqual(getDomainsOfRemotes(remote('git@github.com:Microsoft/vscode.git'), whitelist), ['github.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('user@git.server.org:project.git'), whitelist), ['server.org']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('git.server2.org:project.git'), whitelist), ['server2.org']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('git@github.com:Microsoft/vscode.git'), allowedDomains), ['github.com']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('user@git.server.org:project.git'), allowedDomains), ['server.org']);
assert.deepStrictEqual(getDomainsOfRemotes(remote('git.server2.org:project.git'), allowedDomains), ['server2.org']);
});
test('Local remotes', function () {
assert.deepStrictEqual(getDomainsOfRemotes(remote('/opt/git/project.git'), whitelist), []);
assert.deepStrictEqual(getDomainsOfRemotes(remote('file:///opt/git/project.git'), whitelist), []);
assert.deepStrictEqual(getDomainsOfRemotes(remote('/opt/git/project.git'), allowedDomains), []);
assert.deepStrictEqual(getDomainsOfRemotes(remote('file:///opt/git/project.git'), allowedDomains), []);
});
test('Multiple remotes', function () {
const config = ['https://github.com/Microsoft/vscode.git', 'https://git.example.com/gitproject.git'].map(remote).join('');
assert.deepStrictEqual(getDomainsOfRemotes(config, whitelist).sort(), ['example.com', 'github.com']);
assert.deepStrictEqual(getDomainsOfRemotes(config, allowedDomains).sort(), ['example.com', 'github.com']);
});
test('Whitelisting', () => {
test('Non allowed domains are anonymized', () => {
const config = ['https://github.com/Microsoft/vscode.git', 'https://git.foobar.com/gitproject.git'].map(remote).join('');
assert.deepStrictEqual(getDomainsOfRemotes(config, whitelist).sort(), ['aaaaaa.aaa', 'github.com']);
assert.deepStrictEqual(getDomainsOfRemotes(config, allowedDomains).sort(), ['aaaaaa.aaa', 'github.com']);
});
test('HTTPS remotes to be hashed', function () {

View File

@@ -15,6 +15,8 @@ suite('Extension Identifier Pattern', () => {
assert.equal(true, regEx.test('PUBLISHER.NAME'));
assert.equal(true, regEx.test('PUBLISHEr.NAMe'));
assert.equal(true, regEx.test('PUBLISHEr.N-AMe'));
assert.equal(true, regEx.test('PUB-LISHEr.NAMe'));
assert.equal(true, regEx.test('PUB-LISHEr.N-AMe'));
assert.equal(true, regEx.test('PUBLISH12Er90.N-A54Me123'));
assert.equal(true, regEx.test('111PUBLISH12Er90.N-1111A54Me123'));
assert.equal(false, regEx.test('publishername'));