Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

- enable sign verification in insiders by default #167188

Merged
merged 1 commit into from Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 22 additions & 1 deletion src/vs/platform/extensionManagement/node/extensionDownloader.ts
Expand Up @@ -10,6 +10,7 @@ import { Schemas } from 'vs/base/common/network';
import { isWindows } from 'vs/base/common/platform';
import { joinPath } from 'vs/base/common/resources';
import * as semver from 'vs/base/common/semver/semver';
import { isBoolean } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { Promises as FSPromises } from 'vs/base/node/pfs';
Expand All @@ -18,8 +19,10 @@ import { INativeEnvironmentService } from 'vs/platform/environment/common/enviro
import { ExtensionManagementError, ExtensionManagementErrorCode, IExtensionGalleryService, IGalleryExtension, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionKey, groupByExtension } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { ExtensionSignatureVerificationError, IExtensionSignatureVerificationService } from 'vs/platform/extensionManagement/node/extensionSignatureVerificationService';
import { TargetPlatform } from 'vs/platform/extensions/common/extensions';
import { IFileService, IFileStatWithMetadata } from 'vs/platform/files/common/files';
import { ILogService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';

export class ExtensionsDownloader extends Disposable {

Expand All @@ -30,10 +33,12 @@ export class ExtensionsDownloader extends Disposable {
private readonly cleanUpPromise: Promise<void>;

constructor(
private readonly targetPlatform: Promise<TargetPlatform>,
@INativeEnvironmentService environmentService: INativeEnvironmentService,
@IFileService private readonly fileService: IFileService,
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IProductService private readonly productService: IProductService,
@IExtensionSignatureVerificationService private readonly extensionSignatureVerificationService: IExtensionSignatureVerificationService,
@ILogService private readonly logService: ILogService,
) {
Expand All @@ -54,7 +59,7 @@ export class ExtensionsDownloader extends Disposable {
}

let verified: boolean = false;
if (extension.isSigned && this.configurationService.getValue('extensions.verifySignature') === true) {
if (await this.checkForVerification(extension)) {
const signatureArchiveLocation = await this.downloadSignatureArchive(extension);
try {
verified = await this.extensionSignatureVerificationService.verify(location.fsPath, signatureArchiveLocation.fsPath);
Expand All @@ -69,6 +74,22 @@ export class ExtensionsDownloader extends Disposable {
return { location, verified };
}

private async checkForVerification(extension: IGalleryExtension): Promise<boolean> {
if (!extension.isSigned) {
return false;
}
const targetPlatform = await this.targetPlatform;
// Signing module has issue in this platform - https://github.com/microsoft/vscode/issues/164726
if (targetPlatform === TargetPlatform.LINUX_ARMHF) {
return false;
}
const value = this.configurationService.getValue('extensions.verifySignature');
if (isBoolean(value)) {
return value;
}
return this.productService.quality !== 'stable';
}

private async downloadSignatureArchive(extension: IGalleryExtension): Promise<URI> {
await this.cleanUpPromise;

Expand Down
Expand Up @@ -87,7 +87,7 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi
const extensionLifecycle = this._register(instantiationService.createInstance(ExtensionsLifecycle));
this.extensionsScanner = this._register(instantiationService.createInstance(ExtensionsScanner, extension => extensionLifecycle.postUninstall(extension)));
this.manifestCache = this._register(new ExtensionsManifestCache(environmentService, this));
this.extensionsDownloader = this._register(instantiationService.createInstance(ExtensionsDownloader));
this.extensionsDownloader = this._register(instantiationService.createInstance(ExtensionsDownloader, this.getTargetPlatform()));

const extensionsWatcher = this._register(new ExtensionsWatcher(this, this.extensionsScannerService, userDataProfilesService, extensionsProfileScannerService, uriIdentityService, fileService, logService));
this._register(extensionsWatcher.onDidChangeExtensionsByAnotherSource(e => this.onDidChangeExtensionsFromAnotherSource(e)));
Expand Down
Expand Up @@ -21,11 +21,13 @@ import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/ex
import { ExtensionsDownloader } from 'vs/platform/extensionManagement/node/extensionDownloader';
import { ExtensionsScanner, InstallGalleryExtensionTask } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { IExtensionSignatureVerificationService } from 'vs/platform/extensionManagement/node/extensionSignatureVerificationService';
import { TargetPlatform } from 'vs/platform/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { FileService } from 'vs/platform/files/common/fileService';
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';

const ROOT = URI.file('tests').with({ scheme: 'vscode-tests' });

Expand Down Expand Up @@ -86,8 +88,17 @@ suite('InstallGalleryExtensionTask Tests', () => {

teardown(() => disposables.clear());

test('if verification is disabled by default, the task skips verification', async () => {
const testObject = new TestInstallGalleryExtensionTask(aGalleryExtension('a', { isSigned: true }), anExtensionsDownloader('error'));
test('if verification is enabled by default, the task completes', async () => {
const testObject = new TestInstallGalleryExtensionTask(aGalleryExtension('a', { isSigned: true }), anExtensionsDownloader(true));

await testObject.run();

assert.strictEqual(testObject.wasVerified, true);
assert.strictEqual(testObject.installed, true);
});

test('if verification is disabled in stable, the task completes', async () => {
const testObject = new TestInstallGalleryExtensionTask(aGalleryExtension('a', { isSigned: true }), anExtensionsDownloader('error', undefined, 'stable'));

await testObject.run();

Expand Down Expand Up @@ -160,13 +171,14 @@ suite('InstallGalleryExtensionTask Tests', () => {
assert.strictEqual(testObject.installed, true);
});

function anExtensionsDownloader(verificationResult: string | boolean, isSignatureVerificationEnabled?: boolean): ExtensionsDownloader {
function anExtensionsDownloader(verificationResult: string | boolean, isSignatureVerificationEnabled?: boolean, quality?: string): ExtensionsDownloader {
const logService = new NullLogService();
const fileService = disposables.add(new FileService(logService));
const fileSystemProvider = disposables.add(new InMemoryFileSystemProvider());
fileService.registerProvider(ROOT.scheme, fileSystemProvider);

const instantiationService = new TestInstantiationService();
instantiationService.stub(IProductService, { quality: quality ?? 'insiders' });
instantiationService.stub(IFileService, fileService);
instantiationService.stub(ILogService, logService);
instantiationService.stub(INativeEnvironmentService, <Partial<INativeEnvironmentService>>{ extensionsDownloadLocation: joinPath(ROOT, 'CachedExtensionVSIXs') });
Expand All @@ -180,7 +192,7 @@ suite('InstallGalleryExtensionTask Tests', () => {
});
instantiationService.stub(IConfigurationService, new TestConfigurationService(isBoolean(isSignatureVerificationEnabled) ? { extensions: { verifySignature: isSignatureVerificationEnabled } } : undefined));
instantiationService.stub(IExtensionSignatureVerificationService, new TestExtensionSignatureVerificationService(verificationResult));
return instantiationService.createInstance(ExtensionsDownloader);
return instantiationService.createInstance(ExtensionsDownloader, Promise.resolve(TargetPlatform.LINUX_X64));
}

function aGalleryExtension(name: string, properties: Partial<IGalleryExtension> = {}, galleryExtensionProperties: any = {}, assets: Partial<IGalleryExtensionAssets> = {}): IGalleryExtension {
Expand Down