Skip to content

Commit 499565a

Browse files
Webview resources (microsoft#375)
* Update typing for vscode api * Webviews will load ressources from webviewUri instead of hardcoded vscode-ressources * Add script security policy with CSP * Add link to sample code
1 parent b379e05 commit 499565a

7 files changed

Lines changed: 65 additions & 46 deletions

File tree

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@
257257
"@types/node": "^10.12.21",
258258
"@types/react": "16.8.6",
259259
"@types/react-dom": "16.8.4",
260-
"@types/vscode": "^1.34.0",
260+
"@types/vscode": "^1.45.1",
261261
"css-loader": "^1.0.0",
262262
"del": "^4.0.0",
263263
"event-stream": "^4.0.1",

src/constants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ export const CONSTANTS = {
4040
MICROBIT: "micro:bit",
4141
CLUE: "CLUE",
4242
},
43+
SCRIPT_PATH: {
44+
SIMULATOR: "out/simulator.js",
45+
VSCODE_API: "out/vscode_import.js",
46+
},
4347
ERROR: {
4448
BAD_PYTHON_PATH:
4549
'Your interpreter is not pointing to a valid Python executable. Please select a different interpreter (CTRL+SHIFT+P and type "python.selectInterpreter") and restart the application',

src/extension.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ export async function activate(context: vscode.ExtensionContext) {
134134
messagingService.setWebview(currentPanel.webview);
135135
currentPanel.webview.html = webviewService.getWebviewContent(
136136
WEBVIEW_TYPES.SIMULATOR,
137-
true
137+
true,
138+
currentPanel
138139
);
139140
currentPanel.reveal(vscode.ViewColumn.Beside);
140141
} else {
@@ -158,7 +159,8 @@ export async function activate(context: vscode.ExtensionContext) {
158159

159160
currentPanel.webview.html = webviewService.getWebviewContent(
160161
WEBVIEW_TYPES.SIMULATOR,
161-
true
162+
true,
163+
currentPanel
162164
);
163165
messagingService.setWebview(currentPanel.webview);
164166

src/service/webviewService.ts

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -26,35 +26,44 @@ export class WebviewService {
2626
}
2727
}
2828

29-
public getWebviewContent(webviewType: string, hasDevice: boolean) {
29+
public getWebviewContent(
30+
webviewType: string,
31+
hasDevice: boolean,
32+
panel: vscode.WebviewPanel
33+
) {
34+
const onDiskPath = vscode.Uri.file(
35+
this.context.asAbsolutePath(CONSTANTS.SCRIPT_PATH.SIMULATOR)
36+
);
37+
const scriptSrc = panel.webview.asWebviewUri(onDiskPath);
38+
39+
const vscodeImportPath = vscode.Uri.file(
40+
this.context.asAbsolutePath(CONSTANTS.SCRIPT_PATH.VSCODE_API)
41+
);
42+
const vscodeImportPathSrc = panel.webview.asWebviewUri(
43+
vscodeImportPath
44+
);
45+
46+
const attributeString = this.getAttributeString(webviewType, hasDevice);
47+
const nonce = getNonce();
48+
3049
return `<!DOCTYPE html>
3150
<html lang="en">
3251
<head>
3352
<meta charset="UTF-8">
3453
<meta name="viewport" content="width=device-width, initial-scale=1.0">
35-
54+
<meta
55+
http-equiv="Content-Security-Policy"
56+
content=" script-src ${panel.webview.cspSource} nonce-${nonce}"
57+
/>
3658
<title>${CONSTANTS.NAME}</title>
3759
</head>
3860
<body>
3961
<div id="root"></div>
40-
<script >
41-
const vscode = acquireVsCodeApi();
42-
</script>
43-
<script ></script>
44-
${this.loadScript(
45-
this.context,
46-
webviewType,
47-
"out/vendor.js",
48-
hasDevice
49-
)}
50-
${this.loadScript(
51-
this.context,
52-
webviewType,
53-
"out/simulator.js",
54-
hasDevice
55-
)}
56-
</body>
57-
</html>`;
62+
<script nonce="${nonce}" src=${vscodeImportPathSrc} ></script>
63+
<script nonce="${nonce}" src=${scriptSrc} ${attributeString} ></script>
64+
65+
</body>
66+
< /html>`;
5867
}
5968

6069
private createTutorialPanel() {
@@ -69,7 +78,8 @@ export class WebviewService {
6978
);
7079
this.tutorialPanel.webview.html = this.getWebviewContent(
7180
WEBVIEW_TYPES.GETTING_STARTED,
72-
false
81+
false,
82+
this.tutorialPanel
7383
);
7484
this.tutorialPanel.onDidDispose(() => {
7585
this.disposeTutorialPanel();
@@ -79,27 +89,24 @@ export class WebviewService {
7989
private disposeTutorialPanel() {
8090
this.tutorialPanel = undefined;
8191
}
82-
83-
private loadScript(
84-
context: vscode.ExtensionContext,
85-
attributeValue: string,
86-
scriptPath: string,
87-
hasDevice: boolean
88-
) {
89-
let attributeString: string;
92+
private getAttributeString(webviewType: string, hasDevice: boolean) {
9093
if (hasDevice) {
91-
attributeString = `${
92-
WEBVIEW_ATTRIBUTES_KEY.TYPE
93-
}=${attributeValue} ${
94+
return `${WEBVIEW_ATTRIBUTES_KEY.TYPE}=${webviewType} ${
9495
WEBVIEW_ATTRIBUTES_KEY.INITIAL_DEVICE
95-
}=${this.deviceSelectionService.getCurrentActiveDevice()}`;
96+
}=${this.deviceSelectionService.getCurrentActiveDevice()} `;
9697
} else {
97-
attributeString = `${WEBVIEW_ATTRIBUTES_KEY.TYPE}=${attributeValue} `;
98+
return `${WEBVIEW_ATTRIBUTES_KEY.TYPE}=${webviewType} `;
9899
}
99-
return `<script ${attributeString} src="${vscode.Uri.file(
100-
context.asAbsolutePath(scriptPath)
101-
)
102-
.with({ scheme: "vscode-resource" })
103-
.toString()}"></script>`;
104100
}
105101
}
102+
// Nonce generator taken from vscode extension samples found here:
103+
// https://github.com/microsoft/vscode-extension-samples/blob/master/custom-editor-sample/src/util.ts
104+
function getNonce() {
105+
let text = "";
106+
const possible =
107+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
108+
for (let i = 0; i < 32; i++) {
109+
text += possible.charAt(Math.floor(Math.random() * possible.length));
110+
}
111+
return text;
112+
}

src/vscode_import.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare const acquireVsCodeApi;
2+
3+
const vscode = acquireVsCodeApi();

webpack.config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ module.exports = {
99
path: path.resolve(__dirname, "out"),
1010
filename: "[name].js"
1111
},
12-
devtool: "eval-source-map",
12+
devServer: {
13+
historyApiFallback: true
14+
},
15+
devtool: "source-map",
1316
resolve: {
1417
extensions: [".js", ".ts", ".tsx", ".json"]
1518
},

0 commit comments

Comments
 (0)