Adopt uuids for generating webview nonces

This commit is contained in:
Matt Bierner 2025-10-29 13:53:47 -07:00
parent f8e2f71c2f
commit c47a56c7bc
No known key found for this signature in database
GPG Key ID: 87BD15F7203A4CF2
17 changed files with 291 additions and 45 deletions

View File

@ -8,8 +8,9 @@ import * as uri from 'vscode-uri';
import { ILogger } from '../logging';
import { MarkdownItEngine } from '../markdownEngine';
import { MarkdownContributionProvider } from '../markdownExtensions';
import { escapeAttribute, getNonce } from '../util/dom';
import { escapeAttribute } from '../util/dom';
import { WebviewResourceProvider } from '../util/resources';
import { generateUuid } from '../util/uuid';
import { MarkdownPreviewConfiguration, MarkdownPreviewConfigurationManager } from './previewConfig';
import { ContentSecurityPolicyArbiter, MarkdownPreviewSecurityLevel } from './security';
@ -82,7 +83,7 @@ export class MdDocumentRenderer {
this._logger.trace('DocumentRenderer', `provideTextDocumentContent - ${markdownDocument.uri}`, initialData);
// Content Security Policy
const nonce = getNonce();
const nonce = generateUuid();
const csp = this._getCsp(resourceProvider, sourceUri, nonce);
const body = await this.renderBody(markdownDocument, resourceProvider);

View File

@ -11,11 +11,3 @@ export function escapeAttribute(value: string | vscode.Uri): string {
.replace(/'/g, ''');
}
export function getNonce() {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 64; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}

View File

@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* Copied from src/vs/base/common/uuid.ts
*/
export function generateUuid(): string {
// use `randomUUID` if possible
if (typeof crypto.randomUUID === 'function') {
// see https://developer.mozilla.org/en-US/docs/Web/API/Window/crypto
// > Although crypto is available on all windows, the returned Crypto object only has one
// > usable feature in insecure contexts: the getRandomValues() method.
// > In general, you should use this API only in secure contexts.
return crypto.randomUUID.bind(crypto)();
}
// prep-work
const _data = new Uint8Array(16);
const _hex: string[] = [];
for (let i = 0; i < 256; i++) {
_hex.push(i.toString(16).padStart(2, '0'));
}
// get data
crypto.getRandomValues(_data);
// set version bits
_data[6] = (_data[6] & 0x0f) | 0x40;
_data[8] = (_data[8] & 0x3f) | 0x80;
// print as string
let i = 0;
let result = '';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
return result;
}

View File

@ -12,6 +12,9 @@
"@vscode/extension-telemetry": "^0.9.8",
"vscode-uri": "^3.0.6"
},
"devDependencies": {
"@types/node": "22.x"
},
"engines": {
"vscode": "^1.70.0"
}
@ -140,6 +143,16 @@
"integrity": "sha512-OUUJTh3fnaUSzg9DEHgv3d7jC+DnPL65mIO7RaR+jWve7+MmcgIvF79gY97DPQ4frH+IpNR78YAYd/dW4gK3kg==",
"license": "MIT"
},
"node_modules/@types/node": {
"version": "22.18.13",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.13.tgz",
"integrity": "sha512-Bo45YKIjnmFtv6I1TuC8AaHBbqXtIo+Om5fE4QiU1Tj8QR/qt+8O3BAtOimG5IFmwaWiPmB3Mv3jtYzBA4Us2A==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/@vscode/extension-telemetry": {
"version": "0.9.8",
"resolved": "https://registry.npmjs.org/@vscode/extension-telemetry/-/extension-telemetry-0.9.8.tgz",
@ -154,6 +167,13 @@
"vscode": "^1.75.0"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
},
"node_modules/vscode-uri": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.6.tgz",

View File

@ -163,6 +163,9 @@
"@vscode/extension-telemetry": "^0.9.8",
"vscode-uri": "^3.0.6"
},
"devDependencies": {
"@types/node": "22.x"
},
"repository": {
"type": "git",
"url": "https://github.com/microsoft/vscode.git"

View File

@ -6,7 +6,8 @@
import * as vscode from 'vscode';
import { BinarySizeStatusBarEntry } from './binarySizeStatusBarEntry';
import { MediaPreview, reopenAsText } from './mediaPreview';
import { escapeAttribute, getNonce } from './util/dom';
import { escapeAttribute } from './util/dom';
import { generateUuid } from './util/uuid';
class AudioPreviewProvider implements vscode.CustomReadonlyEditorProvider {
@ -57,7 +58,7 @@ class AudioPreview extends MediaPreview {
src: await this.getResourcePath(this._webviewEditor, this._resource, version),
};
const nonce = getNonce();
const nonce = generateUuid();
const cspSource = this._webviewEditor.webview.cspSource;
return /* html */`<!DOCTYPE html>

View File

@ -6,7 +6,8 @@
import * as vscode from 'vscode';
import { BinarySizeStatusBarEntry } from '../binarySizeStatusBarEntry';
import { MediaPreview, PreviewState, reopenAsText } from '../mediaPreview';
import { escapeAttribute, getNonce } from '../util/dom';
import { escapeAttribute } from '../util/dom';
import { generateUuid } from '../util/uuid';
import { SizeStatusBarEntry } from './sizeStatusBarEntry';
import { Scale, ZoomStatusBarEntry } from './zoomStatusBarEntry';
@ -184,7 +185,7 @@ class ImagePreview extends MediaPreview {
src: await this.getResourcePath(this._webviewEditor, this._resource, version),
};
const nonce = getNonce();
const nonce = generateUuid();
const cspSource = this._webviewEditor.webview.cspSource;
return /* html */`<!DOCTYPE html>

View File

@ -7,12 +7,3 @@ import * as vscode from 'vscode';
export function escapeAttribute(value: string | vscode.Uri): string {
return value.toString().replace(/"/g, '&quot;');
}
export function getNonce() {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 64; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}

View File

@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* Copied from src/vs/base/common/uuid.ts
*/
export function generateUuid(): string {
// use `randomUUID` if possible
if (typeof crypto.randomUUID === 'function') {
// see https://developer.mozilla.org/en-US/docs/Web/API/Window/crypto
// > Although crypto is available on all windows, the returned Crypto object only has one
// > usable feature in insecure contexts: the getRandomValues() method.
// > In general, you should use this API only in secure contexts.
return crypto.randomUUID.bind(crypto)();
}
// prep-work
const _data = new Uint8Array(16);
const _hex: string[] = [];
for (let i = 0; i < 256; i++) {
_hex.push(i.toString(16).padStart(2, '0'));
}
// get data
crypto.getRandomValues(_data);
// set version bits
_data[6] = (_data[6] & 0x0f) | 0x40;
_data[8] = (_data[8] & 0x3f) | 0x80;
// print as string
let i = 0;
let result = '';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
return result;
}

View File

@ -6,7 +6,8 @@
import * as vscode from 'vscode';
import { BinarySizeStatusBarEntry } from './binarySizeStatusBarEntry';
import { MediaPreview, reopenAsText } from './mediaPreview';
import { escapeAttribute, getNonce } from './util/dom';
import { escapeAttribute } from './util/dom';
import { generateUuid } from './util/uuid';
class VideoPreviewProvider implements vscode.CustomReadonlyEditorProvider {
@ -61,7 +62,7 @@ class VideoPreview extends MediaPreview {
loop: configurations.get('loop'),
};
const nonce = getNonce();
const nonce = generateUuid();
const cspSource = this._webviewEditor.webview.cspSource;
return /* html */`<!DOCTYPE html>

View File

@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { generateUuid } from './uuid';
/**
* View type that uniquely identifies the Mermaid chat output renderer.
@ -42,7 +43,7 @@ export function activate(context: vscode.ExtensionContext) {
};
// Set the HTML content for the webview
const nonce = getNonce();
const nonce = generateUuid();
const mermaidScript = vscode.Uri.joinPath(mediaRoot, 'index.js');
webview.html = `
@ -96,11 +97,4 @@ function escapeHtmlText(str: string): string {
.replace(/'/g, '&#39;');
}
function getNonce() {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 64; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}

View File

@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* Copied from src/vs/base/common/uuid.ts
*/
export function generateUuid(): string {
// use `randomUUID` if possible
if (typeof crypto.randomUUID === 'function') {
// see https://developer.mozilla.org/en-US/docs/Web/API/Window/crypto
// > Although crypto is available on all windows, the returned Crypto object only has one
// > usable feature in insecure contexts: the getRandomValues() method.
// > In general, you should use this API only in secure contexts.
return crypto.randomUUID.bind(crypto)();
}
// prep-work
const _data = new Uint8Array(16);
const _hex: string[] = [];
for (let i = 0; i < 256; i++) {
_hex.push(i.toString(16).padStart(2, '0'));
}
// get data
crypto.getRandomValues(_data);
// set version bits
_data[6] = (_data[6] & 0x0f) | 0x40;
_data[8] = (_data[8] & 0x3f) | 0x80;
// print as string
let i = 0;
let result = '';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
return result;
}

View File

@ -12,6 +12,7 @@
"@vscode/extension-telemetry": "^0.9.8"
},
"devDependencies": {
"@types/node": "22.x",
"@types/vscode-webview": "^1.57.0",
"@vscode/codicons": "^0.0.36"
},
@ -143,6 +144,16 @@
"integrity": "sha512-OUUJTh3fnaUSzg9DEHgv3d7jC+DnPL65mIO7RaR+jWve7+MmcgIvF79gY97DPQ4frH+IpNR78YAYd/dW4gK3kg==",
"license": "MIT"
},
"node_modules/@types/node": {
"version": "22.18.13",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.13.tgz",
"integrity": "sha512-Bo45YKIjnmFtv6I1TuC8AaHBbqXtIo+Om5fE4QiU1Tj8QR/qt+8O3BAtOimG5IFmwaWiPmB3Mv3jtYzBA4Us2A==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/@types/vscode-webview": {
"version": "1.57.0",
"resolved": "https://registry.npmjs.org/@types/vscode-webview/-/vscode-webview-1.57.0.tgz",
@ -169,6 +180,13 @@
"engines": {
"vscode": "^1.75.0"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
}
}
}

View File

@ -69,6 +69,7 @@
"@vscode/extension-telemetry": "^0.9.8"
},
"devDependencies": {
"@types/node": "22.x",
"@types/vscode-webview": "^1.57.0",
"@vscode/codicons": "^0.0.36"
},

View File

@ -5,6 +5,7 @@
import * as vscode from 'vscode';
import { Disposable } from './dispose';
import { generateUuid } from './uuid';
export interface ShowOptions {
@ -112,7 +113,7 @@ export class SimpleBrowserView extends Disposable {
private getHtml(url: string) {
const configuration = vscode.workspace.getConfiguration('simpleBrowser');
const nonce = getNonce();
const nonce = generateUuid();
const mainJs = this.extensionResourceUrl('media', 'index.js');
const mainCss = this.extensionResourceUrl('media', 'main.css');
@ -181,12 +182,3 @@ export class SimpleBrowserView extends Disposable {
function escapeAttribute(value: string | vscode.Uri): string {
return value.toString().replace(/"/g, '&quot;');
}
function getNonce() {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 64; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}

View File

@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* Copied from src/vs/base/common/uuid.ts
*/
export function generateUuid(): string {
// use `randomUUID` if possible
if (typeof crypto.randomUUID === 'function') {
// see https://developer.mozilla.org/en-US/docs/Web/API/Window/crypto
// > Although crypto is available on all windows, the returned Crypto object only has one
// > usable feature in insecure contexts: the getRandomValues() method.
// > In general, you should use this API only in secure contexts.
return crypto.randomUUID.bind(crypto)();
}
// prep-work
const _data = new Uint8Array(16);
const _hex: string[] = [];
for (let i = 0; i < 256; i++) {
_hex.push(i.toString(16).padStart(2, '0'));
}
// get data
crypto.getRandomValues(_data);
// set version bits
_data[6] = (_data[6] & 0x0f) | 0x40;
_data[8] = (_data[8] & 0x3f) | 0x80;
// print as string
let i = 0;
let result = '';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += '-';
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
result += _hex[_data[i++]];
return result;
}

View File

@ -2,7 +2,6 @@
"extends": "../tsconfig.base.json",
"compilerOptions": {
"outDir": "./out",
"types": [],
"typeRoots": [
"./node_modules/@types"
]