提交 386f31a1 编写于 作者: J Joao Moreno

malicious in UI

上级 d536410f
......@@ -373,6 +373,8 @@ export class ExtensionManagementService implements IExtensionManagementService {
}
private installExtension(installableExtension: InstallableExtension): TPromise<ILocalExtension> {
// BLOCK REPORTED EXTENSIONS HERE?
return this.unsetUninstalledAndGetLocal(installableExtension.id)
.then(
local => {
......
......@@ -33,7 +33,7 @@ import { Renderer, DataSource, Controller } from 'vs/workbench/parts/extensions/
import { RatingsWidget, InstallCountWidget } from 'vs/workbench/parts/extensions/browser/extensionsWidgets';
import { EditorOptions } from 'vs/workbench/common/editor';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { CombinedInstallAction, UpdateAction, EnableAction, DisableAction, BuiltinStatusLabelAction, ReloadAction } from 'vs/workbench/parts/extensions/browser/extensionsActions';
import { CombinedInstallAction, UpdateAction, EnableAction, DisableAction, BuiltinStatusLabelAction, ReloadAction, MaliciousStatusLabelAction } from 'vs/workbench/parts/extensions/browser/extensionsActions';
import WebView from 'vs/workbench/parts/html/browser/webview';
import { KeybindingIO } from 'vs/workbench/services/keybinding/common/keybindingIO';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
......@@ -344,6 +344,7 @@ export class ExtensionEditor extends BaseEditor {
this.transientDisposables.push(ratings);
const builtinStatusAction = this.instantiationService.createInstance(BuiltinStatusLabelAction);
const maliciousStatusAction = this.instantiationService.createInstance(MaliciousStatusLabelAction, true);
const installAction = this.instantiationService.createInstance(CombinedInstallAction);
const updateAction = this.instantiationService.createInstance(UpdateAction);
const enableAction = this.instantiationService.createInstance(EnableAction);
......@@ -352,14 +353,15 @@ export class ExtensionEditor extends BaseEditor {
installAction.extension = extension;
builtinStatusAction.extension = extension;
maliciousStatusAction.extension = extension;
updateAction.extension = extension;
enableAction.extension = extension;
disableAction.extension = extension;
reloadAction.extension = extension;
this.extensionActionBar.clear();
this.extensionActionBar.push([reloadAction, updateAction, enableAction, disableAction, installAction, builtinStatusAction], { icon: true, label: true });
this.transientDisposables.push(enableAction, updateAction, reloadAction, disableAction, installAction, builtinStatusAction);
this.extensionActionBar.push([reloadAction, updateAction, enableAction, disableAction, installAction, builtinStatusAction, maliciousStatusAction], { icon: true, label: true });
this.transientDisposables.push(enableAction, updateAction, reloadAction, disableAction, installAction, builtinStatusAction, maliciousStatusAction);
this.navbar.clear();
this.navbar.onChange(this.onNavbarChange.bind(this, extension), this, this.transientDisposables);
......
......@@ -1555,6 +1555,34 @@ export class BuiltinStatusLabelAction extends Action {
}
}
export class MaliciousStatusLabelAction extends Action {
private static readonly Class = 'malicious-status';
private _extension: IExtension;
get extension(): IExtension { return this._extension; }
set extension(extension: IExtension) { this._extension = extension; this.update(); }
constructor(long: boolean) {
const tooltip = localize('malicious tooltip', "This extension was reported to be malicious.");
const label = long ? tooltip : localize('malicious', "Malicious");
super('extensions.install', label, '', false);
this.tooltip = localize('malicious tooltip', "This extension was reported to be malicious.");
}
private update(): void {
if (this.extension && this.extension.isMalicious) {
this.class = `${MaliciousStatusLabelAction.Class} malicious`;
} else {
this.class = `${MaliciousStatusLabelAction.Class} not-malicious`;
}
}
run(): TPromise<any> {
return TPromise.as(null);
}
}
export class DisableAllAction extends Action {
static readonly ID = 'workbench.extensions.action.disableAll';
......
......@@ -16,7 +16,7 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
import { once } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { IExtension, IExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/common/extensions';
import { InstallAction, UpdateAction, BuiltinStatusLabelAction, ManageExtensionAction, ReloadAction, extensionButtonProminentBackground, extensionButtonProminentForeground } from 'vs/workbench/parts/extensions/browser/extensionsActions';
import { InstallAction, UpdateAction, BuiltinStatusLabelAction, ManageExtensionAction, ReloadAction, extensionButtonProminentBackground, extensionButtonProminentForeground, MaliciousStatusLabelAction } from 'vs/workbench/parts/extensions/browser/extensionsActions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { Label, RatingsWidget, InstallCountWidget } from 'vs/workbench/parts/extensions/browser/extensionsWidgets';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
......@@ -97,13 +97,14 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
const ratingsWidget = this.instantiationService.createInstance(RatingsWidget, ratings, { small: true });
const builtinStatusAction = this.instantiationService.createInstance(BuiltinStatusLabelAction);
const maliciousStatusAction = this.instantiationService.createInstance(MaliciousStatusLabelAction, false);
const installAction = this.instantiationService.createInstance(InstallAction);
const updateAction = this.instantiationService.createInstance(UpdateAction);
const reloadAction = this.instantiationService.createInstance(ReloadAction);
const manageAction = this.instantiationService.createInstance(ManageExtensionAction);
actionbar.push([reloadAction, updateAction, installAction, builtinStatusAction, manageAction], actionOptions);
const disposables = [versionWidget, installCountWidget, ratingsWidget, builtinStatusAction, updateAction, reloadAction, manageAction, actionbar, bookmarkStyler];
actionbar.push([reloadAction, updateAction, installAction, builtinStatusAction, maliciousStatusAction, manageAction], actionOptions);
const disposables = [versionWidget, installCountWidget, ratingsWidget, builtinStatusAction, maliciousStatusAction, updateAction, reloadAction, manageAction, actionbar, bookmarkStyler];
return {
root, element, icon, name, installCount, ratings, author, description, disposables,
......@@ -113,6 +114,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
installCountWidget.extension = extension;
ratingsWidget.extension = extension;
builtinStatusAction.extension = extension;
maliciousStatusAction.extension = extension;
installAction.extension = extension;
updateAction.extension = extension;
reloadAction.extension = extension;
......
......@@ -30,11 +30,13 @@
.monaco-action-bar .action-item.disabled .action-label.extension-action.enable,
.monaco-action-bar .action-item.disabled .action-label.extension-action.disable,
.monaco-action-bar .action-item.disabled .action-label.extension-action.reload,
.monaco-action-bar .action-item.disabled .action-label.built-in-status.user {
.monaco-action-bar .action-item.disabled .action-label.built-in-status.user,
.monaco-action-bar .action-item.disabled .action-label.malicious-status.not-malicious {
display: none;
}
.monaco-action-bar .action-item .action-label.built-in-status {
.monaco-action-bar .action-item .action-label.built-in-status
.monaco-action-bar .action-item .action-label.malicious-status {
border-radius: 4px;
color: inherit;
background-color: transparent;
......@@ -44,7 +46,8 @@
line-height: initial;
}
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.built-in-status {
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.built-in-status,
.extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.malicious-status {
font-weight: normal;
}
......
......@@ -52,6 +52,7 @@ export interface IExtension {
getReadme(): TPromise<string>;
getChangelog(): TPromise<string>;
local?: ILocalExtension;
isMalicious: boolean;
}
export interface IExtensionDependencies {
......
......@@ -37,8 +37,8 @@ import product from 'vs/platform/node/product';
import { ILogService } from 'vs/platform/log/common/log';
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
interface IExtensionStateProvider {
(extension: Extension): ExtensionState;
interface IExtensionStateProvider<T> {
(extension: Extension): T;
}
class Extension implements IExtension {
......@@ -47,7 +47,8 @@ class Extension implements IExtension {
constructor(
private galleryService: IExtensionGalleryService,
private stateProvider: IExtensionStateProvider,
private stateProvider: IExtensionStateProvider<ExtensionState>,
private maliciousStateProvider: IExtensionStateProvider<boolean>,
public local: ILocalExtension,
public gallery: IGalleryExtension,
private telemetryService: ITelemetryService
......@@ -153,6 +154,10 @@ class Extension implements IExtension {
return this.stateProvider(this);
}
get isMalicious(): boolean {
return this.maliciousStateProvider(this);
}
get installCount(): number {
return this.gallery ? this.gallery.installCount : null;
}
......@@ -321,7 +326,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
private static readonly SyncPeriod = 1000 * 60 * 60 * 12; // 12 hours
_serviceBrand: any;
private stateProvider: IExtensionStateProvider;
private stateProvider: IExtensionStateProvider<ExtensionState>;
private installing: IActiveExtension[] = [];
private uninstalling: IActiveExtension[] = [];
private installed: Extension[] = [];
......@@ -332,6 +337,9 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
private _onChange: Emitter<void> = new Emitter<void>();
get onChange(): Event<void> { return this._onChange.event; }
private maliciousExtensions = new Set<string>();
private maliciousStateProvider: IExtensionStateProvider<boolean>;
private _extensionAllowedBadgeProviders: string[];
constructor(
......@@ -350,6 +358,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
@IProgressService2 private progressService: IProgressService2
) {
this.stateProvider = ext => this.getExtensionState(ext);
this.maliciousStateProvider = ext => this.maliciousExtensions.has(ext.id);
extensionService.onInstallExtension(this.onInstallExtension, this, this.disposables);
extensionService.onDidInstallExtension(this.onDidInstallExtension, this, this.disposables);
......@@ -384,30 +393,34 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
}
queryLocal(): TPromise<IExtension[]> {
return this.extensionService.getInstalled().then(result => {
const installedById = index(this.installed, e => e.local.identifier.id);
this.installed = result.map(local => {
const extension = installedById[local.identifier.id] || new Extension(this.galleryService, this.stateProvider, local, null, this.telemetryService);
extension.local = local;
extension.enablementState = this.extensionEnablementService.getEnablementState({ id: extension.id, uuid: extension.uuid });
return extension;
});
return this.updateExtensionsReport().then(() => {
return this.extensionService.getInstalled().then(result => {
const installedById = index(this.installed, e => e.local.identifier.id);
this.installed = result.map(local => {
const extension = installedById[local.identifier.id] || new Extension(this.galleryService, this.stateProvider, this.maliciousStateProvider, local, null, this.telemetryService);
extension.local = local;
extension.enablementState = this.extensionEnablementService.getEnablementState({ id: extension.id, uuid: extension.uuid });
return extension;
});
this._onChange.fire();
return this.local;
this._onChange.fire();
return this.local;
});
});
}
queryGallery(options: IQueryOptions = {}): TPromise<IPager<IExtension>> {
return this.galleryService.query(options)
.then(result => mapPager(result, gallery => this.fromGallery(gallery)))
.then(null, err => {
if (/No extension gallery service configured/.test(err.message)) {
return TPromise.as(singlePagePager([]));
}
return this.updateExtensionsReport().then(() => {
return this.galleryService.query(options)
.then(result => mapPager(result, gallery => this.fromGallery(gallery)))
.then(null, err => {
if (/No extension gallery service configured/.test(err.message)) {
return TPromise.as(singlePagePager([]));
}
return TPromise.wrapError<IPager<IExtension>>(err);
});
return TPromise.wrapError<IPager<IExtension>>(err);
});
});
}
loadDependencies(extension: IExtension): TPromise<IExtensionDependencies> {
......@@ -446,7 +459,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
return installed;
}
return new Extension(this.galleryService, this.stateProvider, null, gallery, this.telemetryService);
return new Extension(this.galleryService, this.stateProvider, this.maliciousStateProvider, null, gallery, this.telemetryService);
}
private getInstalledExtensionMatchingGallery(gallery: IGalleryExtension): Extension {
......@@ -533,6 +546,10 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
return false;
}
if (this.maliciousStateProvider(extension)) {
return false;
}
return !!(extension as Extension).gallery;
}
......@@ -549,6 +566,10 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
return undefined;
}
if (this.maliciousStateProvider(extension)) {
return TPromise.wrapError<void>(new Error(nls.localize('malicious', "This extension is reported to be malicious.")));
}
const ext = extension as Extension;
const gallery = ext.gallery;
......@@ -742,7 +763,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
let extension = this.installed.filter(e => areSameExtensions(e, gallery.identifier))[0];
if (!extension) {
extension = new Extension(this.galleryService, this.stateProvider, null, gallery, this.telemetryService);
extension = new Extension(this.galleryService, this.stateProvider, this.maliciousStateProvider, null, gallery, this.telemetryService);
}
extension.gallery = gallery;
......@@ -757,7 +778,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
private onDidInstallExtension(event: DidInstallExtensionEvent): void {
const { local, zipPath, error, gallery } = event;
const installingExtension = gallery ? this.installing.filter(e => areSameExtensions(e.extension, gallery.identifier))[0] : null;
const extension: Extension = installingExtension ? installingExtension.extension : zipPath ? new Extension(this.galleryService, this.stateProvider, null, null, this.telemetryService) : null;
const extension: Extension = installingExtension ? installingExtension.extension : zipPath ? new Extension(this.galleryService, this.stateProvider, this.maliciousStateProvider, null, null, this.telemetryService) : null;
if (extension) {
this.installing = installingExtension ? this.installing.filter(e => e !== installingExtension) : this.installing;
......@@ -942,6 +963,18 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
}).done(undefined, error => this.onError(error));
}
private updateExtensionsReport(): TPromise<void> {
return this.extensionService.getExtensionsReport().then(report => {
this.maliciousExtensions.clear();
for (const extension of report) {
if (extension.malicious) {
this.maliciousExtensions.add(extension.id.id);
}
}
});
}
dispose(): void {
this.syncDelayer.cancel();
this.disposables = dispose(this.disposables);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册