From 001cff3e78b29ac4975d275cfeaab0f108d80c3a Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 23 Aug 2017 11:00:05 +0200 Subject: [PATCH] know hover providers using command links, #29076 --- src/vs/base/common/htmlContent.ts | 14 +++++++ src/vs/workbench/api/node/extHost.api.impl.ts | 2 +- .../api/node/extHostLanguageFeatures.ts | 37 +++++++++++++------ 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/vs/base/common/htmlContent.ts b/src/vs/base/common/htmlContent.ts index 5f2f9fbeba4..c758efe59c8 100644 --- a/src/vs/base/common/htmlContent.ts +++ b/src/vs/base/common/htmlContent.ts @@ -6,6 +6,7 @@ 'use strict'; import { equals } from 'vs/base/common/arrays'; +import { marked } from 'vs/base/common/marked/marked'; /** * MarkedString can be used to render human readable text. It is either a markdown string @@ -38,3 +39,16 @@ export function removeMarkdownEscapes(text: string): string { } return text.replace(/\\([\\`*_{}[\]()#+\-.!])/g, '$1'); } + +export function containsCommandLink(value: MarkedString): boolean { + let uses = false; + const renderer = new marked.Renderer(); + renderer.link = (href, title, text): string => { + if (href.match(/^command:/i)) { + uses = true; + } + return 'link'; + }; + marked(value, { renderer }); + return uses; +} diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index b18258e2c68..1df16a4716f 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -242,7 +242,7 @@ export function createApiFactory( return languageFeatures.registerTypeDefinitionProvider(selector, provider); }, registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable { - return languageFeatures.registerHoverProvider(selector, provider); + return languageFeatures.registerHoverProvider(selector, provider, extension.id); }, registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable { return languageFeatures.registerDocumentHighlightProvider(selector, provider); diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 8e0c521684c..f6049cdab17 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -18,10 +18,13 @@ import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHos import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics'; import { IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search'; import { asWinJsPromise } from 'vs/base/common/async'; -import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IRawColorFormatMap, IMainContext } from './extHost.protocol'; +import { MainContext, MainThreadTelemetryShape, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IRawColorFormatMap, IMainContext } from './extHost.protocol'; import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings'; import { IPosition } from 'vs/editor/common/core/position'; import { IRange } from 'vs/editor/common/core/range'; +import { containsCommandLink } from 'vs/base/common/htmlContent'; +import { isFalsyOrEmpty } from 'vs/base/common/arrays'; +import { once } from 'vs/base/common/functional'; // --- adapter @@ -173,12 +176,12 @@ class TypeDefinitionAdapter { class HoverAdapter { - private _documents: ExtHostDocuments; - private _provider: vscode.HoverProvider; - - constructor(documents: ExtHostDocuments, provider: vscode.HoverProvider) { - this._documents = documents; - this._provider = provider; + constructor( + private readonly _documents: ExtHostDocuments, + private readonly _provider: vscode.HoverProvider, + private readonly _telemetryLog: (name: string, data: object) => void, + ) { + // } public provideHover(resource: URI, position: IPosition): TPromise { @@ -187,7 +190,7 @@ class HoverAdapter { let pos = TypeConverters.toPosition(position); return asWinJsPromise(token => this._provider.provideHover(doc, pos, token)).then(value => { - if (!value) { + if (!value || isFalsyOrEmpty(value.contents)) { return undefined; } if (!value.range) { @@ -197,7 +200,14 @@ class HoverAdapter { value.range = new Range(pos, pos); } - return TypeConverters.fromHover(value); + const result = TypeConverters.fromHover(value); + + // we wanna know which extension uses command links + // because that is a potential trick-attack on users + if (result.contents.some(containsCommandLink)) { + this._telemetryLog('usesCommandLink', { from: 'hover' }); + } + return result; }); } } @@ -744,6 +754,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { private static _handlePool: number = 0; private _proxy: MainThreadLanguageFeaturesShape; + private _telemetry: MainThreadTelemetryShape; private _documents: ExtHostDocuments; private _commands: ExtHostCommands; private _heapService: ExtHostHeapService; @@ -759,6 +770,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { diagnostics: ExtHostDiagnostics ) { this._proxy = mainContext.get(MainContext.MainThreadLanguageFeatures); + this._telemetry = mainContext.get(MainContext.MainThreadTelemetry); this._documents = documents; this._commands = commands; this._heapService = heapMonitor; @@ -860,9 +872,12 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { // --- extra info - registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable { + registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider, extensionId?: string): vscode.Disposable { const handle = this._nextHandle(); - this._adapter.set(handle, new HoverAdapter(this._documents, provider)); + this._adapter.set(handle, new HoverAdapter(this._documents, provider, once((name, data) => { + data['extension'] = extensionId; + this._telemetry.$publicLog(name, data); + }))); this._proxy.$registerHoverProvider(handle, selector); return this._createDisposable(handle); } -- GitLab