Path: blob/main/extensions/markdown-language-features/src/preview/security.ts
3292 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as vscode from 'vscode';6import { MarkdownPreviewManager } from './previewManager';789export const enum MarkdownPreviewSecurityLevel {10Strict = 0,11AllowInsecureContent = 1,12AllowScriptsAndAllContent = 2,13AllowInsecureLocalContent = 314}1516export interface ContentSecurityPolicyArbiter {17getSecurityLevelForResource(resource: vscode.Uri): MarkdownPreviewSecurityLevel;1819setSecurityLevelForResource(resource: vscode.Uri, level: MarkdownPreviewSecurityLevel): Thenable<void>;2021shouldAllowSvgsForResource(resource: vscode.Uri): void;2223shouldDisableSecurityWarnings(): boolean;2425setShouldDisableSecurityWarning(shouldShow: boolean): Thenable<void>;26}2728export class ExtensionContentSecurityPolicyArbiter implements ContentSecurityPolicyArbiter {29private readonly _old_trusted_workspace_key = 'trusted_preview_workspace:';30private readonly _security_level_key = 'preview_security_level:';31private readonly _should_disable_security_warning_key = 'preview_should_show_security_warning:';3233constructor(34private readonly _globalState: vscode.Memento,35private readonly _workspaceState: vscode.Memento36) { }3738public getSecurityLevelForResource(resource: vscode.Uri): MarkdownPreviewSecurityLevel {39// Use new security level setting first40const level = this._globalState.get<MarkdownPreviewSecurityLevel | undefined>(this._security_level_key + this._getRoot(resource), undefined);41if (typeof level !== 'undefined') {42return level;43}4445// Fallback to old trusted workspace setting46if (this._globalState.get<boolean>(this._old_trusted_workspace_key + this._getRoot(resource), false)) {47return MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent;48}49return MarkdownPreviewSecurityLevel.Strict;50}5152public setSecurityLevelForResource(resource: vscode.Uri, level: MarkdownPreviewSecurityLevel): Thenable<void> {53return this._globalState.update(this._security_level_key + this._getRoot(resource), level);54}5556public shouldAllowSvgsForResource(resource: vscode.Uri) {57const securityLevel = this.getSecurityLevelForResource(resource);58return securityLevel === MarkdownPreviewSecurityLevel.AllowInsecureContent || securityLevel === MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent;59}6061public shouldDisableSecurityWarnings(): boolean {62return this._workspaceState.get<boolean>(this._should_disable_security_warning_key, false);63}6465public setShouldDisableSecurityWarning(disabled: boolean): Thenable<void> {66return this._workspaceState.update(this._should_disable_security_warning_key, disabled);67}6869private _getRoot(resource: vscode.Uri): vscode.Uri {70if (vscode.workspace.workspaceFolders) {71const folderForResource = vscode.workspace.getWorkspaceFolder(resource);72if (folderForResource) {73return folderForResource.uri;74}7576if (vscode.workspace.workspaceFolders.length) {77return vscode.workspace.workspaceFolders[0].uri;78}79}8081return resource;82}83}8485export class PreviewSecuritySelector {8687public constructor(88private readonly _cspArbiter: ContentSecurityPolicyArbiter,89private readonly _webviewManager: MarkdownPreviewManager90) { }9192public async showSecuritySelectorForResource(resource: vscode.Uri): Promise<void> {93interface PreviewSecurityPickItem extends vscode.QuickPickItem {94readonly type: 'moreinfo' | 'toggle' | MarkdownPreviewSecurityLevel;95}9697function markActiveWhen(when: boolean): string {98return when ? '• ' : '';99}100101const currentSecurityLevel = this._cspArbiter.getSecurityLevelForResource(resource);102const selection = await vscode.window.showQuickPick<PreviewSecurityPickItem>(103[104{105type: MarkdownPreviewSecurityLevel.Strict,106label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.Strict) + vscode.l10n.t("Strict"),107description: vscode.l10n.t("Only load secure content"),108}, {109type: MarkdownPreviewSecurityLevel.AllowInsecureLocalContent,110label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.AllowInsecureLocalContent) + vscode.l10n.t("Allow insecure local content"),111description: vscode.l10n.t("Enable loading content over http served from localhost"),112}, {113type: MarkdownPreviewSecurityLevel.AllowInsecureContent,114label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.AllowInsecureContent) + vscode.l10n.t("Allow insecure content"),115description: vscode.l10n.t("Enable loading content over http"),116}, {117type: MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent,118label: markActiveWhen(currentSecurityLevel === MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent) + vscode.l10n.t("Disable"),119description: vscode.l10n.t("Allow all content and script execution. Not recommended"),120}, {121type: 'moreinfo',122label: vscode.l10n.t("More Information"),123description: ''124}, {125type: 'toggle',126label: this._cspArbiter.shouldDisableSecurityWarnings()127? vscode.l10n.t("Enable preview security warnings in this workspace")128: vscode.l10n.t("Disable preview security warning in this workspace"),129description: vscode.l10n.t("Does not affect the content security level")130},131], {132placeHolder: vscode.l10n.t("Select security settings for Markdown previews in this workspace"),133});134if (!selection) {135return;136}137138if (selection.type === 'moreinfo') {139vscode.commands.executeCommand('vscode.open', vscode.Uri.parse('https://go.microsoft.com/fwlink/?linkid=854414'));140return;141}142143if (selection.type === 'toggle') {144this._cspArbiter.setShouldDisableSecurityWarning(!this._cspArbiter.shouldDisableSecurityWarnings());145this._webviewManager.refresh();146return;147} else {148await this._cspArbiter.setSecurityLevelForResource(resource, selection.type);149}150this._webviewManager.refresh();151}152}153154155