Skip to content

Commit 43ee851

Browse files
authored
Specifying webview resources using VS Code APIs (#1118)
`vscode-resource:` -> `webview.asWebviewUri` for futureproofing.
1 parent 6c2988b commit 43ee851

File tree

14 files changed

+68
-71
lines changed

14 files changed

+68
-71
lines changed

src/eventSchemas/commands/searchSchemas.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,12 @@ export async function createSearchSchemasWebView(params: {
5353
)
5454
const baseTemplateFn = _.template(BaseTemplates.SIMPLE_HTML)
5555
const searchTemplate = _.template(SchemaTemplates.SEARCH_TEMPLATE)
56-
const loadScripts = ExtensionUtilities.getScriptsForHtml(['searchSchemasVue.js'])
57-
const loadLibs = ExtensionUtilities.getLibrariesForHtml(['vue.min.js', 'lodash.min.js'])
58-
const loadStylesheets = ExtensionUtilities.getCssForHtml(['searchSchemas.css'])
56+
const loadScripts = ExtensionUtilities.getScriptsForHtml(['searchSchemasVue.js'], view.webview)
57+
const loadLibs = ExtensionUtilities.getLibrariesForHtml(['vue.min.js', 'lodash.min.js'], view.webview)
58+
const loadStylesheets = ExtensionUtilities.getCssForHtml(['searchSchemas.css'], view.webview)
5959

6060
view.webview.html = baseTemplateFn({
61+
cspSource: view.webview.cspSource,
6162
content: searchTemplate({
6263
Header: getPageHeader(registryNames),
6364
SearchInputPlaceholder: localize(

src/eventSchemas/templates/searchSchemasTemplates.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ export class SchemaTemplates {
3030
<input type="submit" :disabled="downloadDisabled" v-on:click="downloadClicked" value="Download Code Bindings">
3131
</div>
3232
<% Libraries.forEach(function(lib) { %>
33-
<script nonce="<%= lib.nonce %>" src="<%= lib.uri %>"></script>
33+
<script src="<%= lib %>"></script>
3434
<% }); %>
3535
<% Scripts.forEach(function(scr) { %>
36-
<script nonce="<%= scr.nonce %>" src="<%= scr.uri %>"></script>
36+
<script src="<%= scr %>"></script>
3737
<% }); %>
3838
<% Stylesheets.forEach(function(scr) { %>
39-
<link rel="stylesheet" type="text/css" href="<%= scr.uri %>">
39+
<link rel="stylesheet" type="text/css" href="<%= scr %>">
4040
<% }); %>
4141
`
4242
}

src/feedback/commands/submitFeedback.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,18 @@ export function submitFeedback(listener?: (message: any) => Promise<void>): vsco
2626
const baseTemplateFn = _.template(BaseTemplates.SIMPLE_HTML)
2727

2828
panel.webview.html = baseTemplateFn({
29+
cspSource: panel.webview.cspSource,
2930
content: '<h1>Loading...</h1>',
3031
})
3132

3233
const feedbackTemplateFn = _.template(FeedbackTemplates.SUBMIT_TEMPLATE)
3334

34-
const loadScripts = ExtensionUtilities.getScriptsForHtml(['submitFeedbackVue.js'])
35-
const loadLibs = ExtensionUtilities.getLibrariesForHtml(['vue.min.js'])
36-
const loadStylesheets = ExtensionUtilities.getCssForHtml(['submitFeedback.css'])
35+
const loadScripts = ExtensionUtilities.getScriptsForHtml(['submitFeedbackVue.js'], panel.webview)
36+
const loadLibs = ExtensionUtilities.getLibrariesForHtml(['vue.min.js'], panel.webview)
37+
const loadStylesheets = ExtensionUtilities.getCssForHtml(['submitFeedback.css'], panel.webview)
3738

3839
panel.webview.html = baseTemplateFn({
40+
cspSource: panel.webview.cspSource,
3941
content: feedbackTemplateFn({
4042
Scripts: loadScripts,
4143
Libraries: loadLibs,

src/feedback/templates/feedbackTemplates.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ export class FeedbackTemplates {
3737
</div>
3838
</div>
3939
<% Libraries.forEach(function(lib) { %>
40-
<script nonce="<%= lib.nonce %>" src="<%= lib.uri %>"></script>
40+
<script src="<%= lib %>"></script>
4141
<% }); %>
4242
<% Scripts.forEach(function(scr) { %>
43-
<script nonce="<%= scr.nonce %>" src="<%= scr.uri %>"></script>
43+
<script src="<%= scr %>"></script>
4444
<% }); %>
4545
<% Stylesheets.forEach(function(scr) { %>
46-
<link rel="stylesheet" type="text/css" href="<%= scr.uri %>">
46+
<link rel="stylesheet" type="text/css" href="<%= scr %>">
4747
<% }); %>
4848
`
4949
}

src/lambda/commands/invokeLambda.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export async function invokeLambda(params: {
6363
const baseTemplateFn = _.template(BaseTemplates.SIMPLE_HTML)
6464

6565
view.webview.html = baseTemplateFn({
66+
cspSource: view.webview.cspSource,
6667
content: '<h1>Loading...</h1>',
6768
})
6869

@@ -92,10 +93,11 @@ export async function invokeLambda(params: {
9293
})
9394
})
9495

95-
const loadScripts = ExtensionUtilities.getScriptsForHtml(['invokeLambdaVue.js'])
96-
const loadLibs = ExtensionUtilities.getLibrariesForHtml(['vue.min.js'])
96+
const loadScripts = ExtensionUtilities.getScriptsForHtml(['invokeLambdaVue.js'], view.webview)
97+
const loadLibs = ExtensionUtilities.getLibrariesForHtml(['vue.min.js'], view.webview)
9798

9899
view.webview.html = baseTemplateFn({
100+
cspSource: view.webview.cspSource,
99101
content: invokeTemplateFn({
100102
FunctionName: functionNode.configuration.FunctionName,
101103
InputSamples: inputs,

src/lambda/models/scriptResource.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/lambda/templates/lambdaTemplates.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ export class LambdaTemplates {
3535
<br />
3636
</div>
3737
<% Libraries.forEach(function(lib) { %>
38-
<script nonce="<%= lib.nonce %>" src="<%= lib.uri %>"></script>
38+
<script src="<%= lib %>"></script>
3939
<% }); %>
4040
<% Scripts.forEach(function(scr) { %>
41-
<script nonce="<%= scr.nonce %>" src="<%= scr.uri %>"></script>
41+
<script src="<%= scr %>"></script>
4242
<% }); %>
4343
`
4444
}

src/shared/extensionUtilities.ts

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import * as os from 'os'
88
import * as path from 'path'
99
import * as vscode from 'vscode'
1010
import * as nls from 'vscode-nls'
11-
import { ScriptResource } from '../lambda/models/scriptResource'
1211
import { ext } from '../shared/extensionGlobals'
1312
import { mostRecentVersionKey, pluginVersion } from './constants'
1413
import { readFileAsString } from './filesystemUtilities'
@@ -17,41 +16,29 @@ import { getLogger } from './logger'
1716
const localize = nls.loadMessageBundle()
1817

1918
export class ExtensionUtilities {
20-
public static getLibrariesForHtml(names: string[]): ScriptResource[] {
19+
public static getLibrariesForHtml(names: string[], webview: vscode.Webview): vscode.Uri[] {
2120
const basePath = path.join(ext.context.extensionPath, 'media', 'libs')
2221

23-
return this.resolveResourceURIs(basePath, names)
22+
return this.resolveResourceURIs(basePath, names, webview)
2423
}
2524

26-
public static getScriptsForHtml(names: string[]): ScriptResource[] {
25+
public static getScriptsForHtml(names: string[], webview: vscode.Webview): vscode.Uri[] {
2726
const basePath = path.join(ext.context.extensionPath, 'media', 'js')
2827

29-
return this.resolveResourceURIs(basePath, names)
28+
return this.resolveResourceURIs(basePath, names, webview)
3029
}
3130

32-
public static getCssForHtml(names: string[]): ScriptResource[] {
31+
public static getCssForHtml(names: string[], webview: vscode.Webview): vscode.Uri[] {
3332
const basePath = path.join(ext.context.extensionPath, 'media', 'css')
3433

35-
return this.resolveResourceURIs(basePath, names)
34+
return this.resolveResourceURIs(basePath, names, webview)
3635
}
3736

38-
public static getNonce(): string {
39-
let text = ''
40-
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
41-
for (let i = 0; i < 32; i++) {
42-
text += possible.charAt(Math.floor(Math.random() * possible.length))
43-
}
44-
45-
return text
46-
}
47-
48-
private static resolveResourceURIs(basePath: string, names: string[]): ScriptResource[] {
49-
const scripts: ScriptResource[] = []
37+
private static resolveResourceURIs(basePath: string, names: string[], webview: vscode.Webview): vscode.Uri[] {
38+
const scripts: vscode.Uri[] = []
5039
_.forEach(names, scriptName => {
5140
const scriptPathOnDisk = vscode.Uri.file(path.join(basePath, scriptName))
52-
const scriptUri = scriptPathOnDisk.with({ scheme: 'vscode-resource' })
53-
const nonce = ExtensionUtilities.getNonce()
54-
scripts.push({ nonce: nonce, uri: scriptUri })
41+
scripts.push(webview.asWebviewUri(scriptPathOnDisk))
5542
})
5643

5744
return scripts
@@ -110,17 +97,17 @@ export async function createQuickStartWebview(
11097
context: vscode.ExtensionContext,
11198
page: string = 'quickStart.html'
11299
): Promise<vscode.WebviewPanel> {
113-
const html = convertExtensionRootTokensToPath(
114-
await readFileAsString(path.join(context.extensionPath, page)),
115-
context.extensionPath
116-
)
117100
// create hidden webview, leave it up to the caller to show
118101
const view = vscode.window.createWebviewPanel(
119102
'html',
120103
localize('AWS.command.quickStart.title', 'AWS Toolkit - Quick Start'),
121104
{ viewColumn: vscode.ViewColumn.Active, preserveFocus: true }
122105
)
123-
view.webview.html = html
106+
view.webview.html = convertExtensionRootTokensToPath(
107+
await readFileAsString(path.join(context.extensionPath, page)),
108+
context.extensionPath,
109+
view.webview
110+
)
124111

125112
return view
126113
}
@@ -132,8 +119,10 @@ export async function createQuickStartWebview(
132119
* @param text Text to scan
133120
* @param basePath Extension path (from extension context)
134121
*/
135-
function convertExtensionRootTokensToPath(text: string, basePath: string): string {
136-
return text.replace(/!!EXTENSIONROOT!!/g, `vscode-resource:${basePath}`)
122+
function convertExtensionRootTokensToPath(text: string, basePath: string, webview: vscode.Webview): string {
123+
return text.replace(/!!EXTENSIONROOT!!(?<restOfUrl>[-a-zA-Z0-9@:%_\+.~#?&//=]*)/g, (matchedString, restOfUrl) => {
124+
return webview.asWebviewUri(vscode.Uri.file(`${basePath}${restOfUrl}`)).toString()
125+
})
137126
}
138127

139128
/**

src/shared/templates/baseTemplates.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,20 @@
44
*/
55

66
export class BaseTemplates {
7-
/* tslint:disable max-line-length */
87
public static readonly SIMPLE_HTML = `
98
<html>
109
<head>
1110
<meta charset="UTF-8">
1211
<meta name="viewport" content="width=device-width, initial-scale=1.0">
13-
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https: data:; script-src vscode-resource: 'self' 'unsafe-eval'; style-src vscode-resource:;">
12+
<meta http-equiv="Content-Security-Policy"
13+
content="default-src 'none';
14+
img-src <%= cspSource %> https: data:;
15+
script-src <%= cspSource %> 'self' 'unsafe-eval';
16+
style-src <%= cspSource %>;"
17+
>
1418
</head>
1519
<body>
1620
<%= content %>
1721
</body>
1822
</html>`
19-
/* tslint:enable max-line-length */
2023
}

src/shared/treeview/webviews/showErrorDetails.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ export async function showErrorDetails(element: ErrorNode) {
2626

2727
try {
2828
const baseTemplateFn = _.template(BaseTemplates.SIMPLE_HTML)
29-
view.webview.html = baseTemplateFn({ content: `<h1>${localize('AWS.message.loading', 'Loading...')}</h1>` })
29+
view.webview.html = baseTemplateFn({
30+
cspSource: view.webview.cspSource,
31+
content: `<h1>${localize('AWS.message.loading', 'Loading...')}</h1>`,
32+
})
3033

3134
const showErrorDetailsTemplateFn = _.template(ErrorTemplates.SHOW_ERROR_DETAILS)
3235
view.webview.html = baseTemplateFn({
36+
cspSource: view.webview.cspSource,
3337
content: showErrorDetailsTemplateFn(element),
3438
})
3539
} catch (err) {
@@ -39,7 +43,10 @@ export async function showErrorDetails(element: ErrorNode) {
3943
logger.error(error.message)
4044

4145
const baseTemplateFn = _.template(BaseTemplates.SIMPLE_HTML)
42-
view.webview.html = baseTemplateFn({ content: `Error displaying error details: ${error.message}` })
46+
view.webview.html = baseTemplateFn({
47+
cspSource: view.webview.cspSource,
48+
content: `Error displaying error details: ${error.message}`,
49+
})
4350
} finally {
4451
recordAwsShowExplorerErrorDetails({ result: showResult })
4552
}

0 commit comments

Comments
 (0)