Skip to content

Commit

Permalink
Snippet and math preview panels use networked resource
Browse files Browse the repository at this point in the history
  • Loading branch information
James-Yu committed Feb 16, 2024
1 parent b4b4304 commit e4e48b1
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 46 deletions.
14 changes: 7 additions & 7 deletions resources/snippetview/snippetview.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; base-uri 'none'; connect-src %VSCODE_CSP%; script-src %VSCODE_CSP% 'unsafe-inline' blob:; style-src %VSCODE_CSP% 'unsafe-inline';">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; base-uri 'none'; connect-src 'self' http://127.0.0.1:* ; script-src 'self' http://127.0.0.1:* 'unsafe-inline' blob:; style-src 'self' http://127.0.0.1:* 'unsafe-inline';">
<script>
var mathSymbolsJsonUrl = '%VSCODE_RES%/snippetview/snippetpanel.json';
var mathSymbolsJsonUrl = 'http://127.0.0.1:%PORT%/snippetview/snippetpanel.json';
</script>
<script src="%VSCODE_RES%/snippetview/snippetview.js" defer></script>
<script src="http://127.0.0.1:%PORT%/snippetview/snippetview.js" defer></script>
<script>
var pdfjsDistUri = '%VSCODE_PDFJS_DIST%';
var pdfjsDistUri = 'http://127.0.0.1:%PORT%';
</script>
<script src="%VSCODE_PDFJS_DIST%/build/pdf.mjs" type="module"></script>
<script src="%VSCODE_RES%/snippetview/pdfrenderer.js" defer></script>
<link rel="stylesheet" href="%VSCODE_RES%/snippetview/snippetview.css">
<script src="http://127.0.0.1:%PORT%/build/pdf.mjs" type="module"></script>
<script src="http://127.0.0.1:%PORT%/snippetview/pdfrenderer.js" defer></script>
<link rel="stylesheet" href="http://127.0.0.1:%PORT%/snippetview/snippetview.css">
</head>
<body>
<div class="tab">
Expand Down
22 changes: 15 additions & 7 deletions src/extras/math-preview-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class MathPreviewPanelSerializer implements vscode.WebviewPanelSerializer {
enableScripts: true,
localResourceRoots: [resourcesFolder(lw.extensionRoot)]
}
panel.webview.html = getHtml(panel.webview)
panel.webview.html = getHtml()
logger.log('Math preview panel: restored')
return Promise.resolve()
}
Expand Down Expand Up @@ -66,7 +66,7 @@ function open() {
}
)
initializePanel(panel)
panel.webview.html = getHtml(panel.webview)
panel.webview.html = getHtml()
const configuration = vscode.workspace.getConfiguration('latex-workshop')
const editorGroup = configuration.get('mathpreviewpanel.editorGroup') as string
if (activeDocument) {
Expand Down Expand Up @@ -130,13 +130,21 @@ function clearCache() {
state.prevMacros = undefined
}

function getHtml(webview: vscode.Webview) {
const jsPath = vscode.Uri.file(path.join(lw.extensionRoot, './resources/mathpreviewpanel/mathpreview.js'))
const jsPathSrc = webview.asWebviewUri(jsPath)
let serverHandlerInserted = false
function getHtml() {
if (serverHandlerInserted === false) {
lw.server.setHandler((url: string) => {
if (url.startsWith('/mathpreviewpanel/')) {
return path.resolve(lw.extensionRoot, 'resources')
}
return undefined
})
serverHandlerInserted = true
}
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; base-uri 'none'; script-src ${webview.cspSource}; img-src data:; style-src 'unsafe-inline';">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; base-uri 'none'; script-src 'self' http://127.0.0.1:*; img-src data:; style-src 'unsafe-inline';">
<meta charset="UTF-8">
<style>
body {
Expand All @@ -148,7 +156,7 @@ function getHtml(webview: vscode.Webview) {
padding-left: 50px;
}
</style>
<script src='${jsPathSrc}' defer></script>
<script src='http://127.0.0.1:${lw.server.getPort().toString()}/mathpreviewpanel/mathpreview.js' defer></script>
</head>
<body>
<div id="mathBlock"><img src="" id="math" /></div>
Expand Down
18 changes: 14 additions & 4 deletions src/extras/snippet-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as vscode from 'vscode'
import { readFileSync } from 'fs'
import * as path from 'path'
import { lw } from '../lw'
import { replaceWebviewPlaceholders } from '../utils/webview'

export {
state,
Expand Down Expand Up @@ -81,7 +80,19 @@ function receive(message: SnippetViewResult) {
}

class SnippetViewProvider implements vscode.WebviewViewProvider {
private serverHandlerInserted = false

public resolveWebviewView(webviewView: vscode.WebviewView) {
if (this.serverHandlerInserted === false) {
lw.server.setHandler((url: string) => {
if (url.startsWith('/snippetview/')) {
return path.resolve(lw.extensionRoot, 'resources')
}
return undefined
})
this.serverHandlerInserted = true
}

state.view = webviewView

webviewView.webview.options = {
Expand All @@ -93,9 +104,8 @@ class SnippetViewProvider implements vscode.WebviewViewProvider {
})

const webviewSourcePath = path.join(lw.extensionRoot, 'resources', 'snippetview', 'snippetview.html')
let webviewHtml = readFileSync(webviewSourcePath, { encoding: 'utf8' })
webviewHtml = replaceWebviewPlaceholders(webviewHtml, state.view.webview)
webviewView.webview.html = webviewHtml
webviewView.webview.html = readFileSync(webviewSourcePath, { encoding: 'utf8' })
.replaceAll('%PORT%', lw.server.getPort().toString())

webviewView.webview.onDidReceiveMessage((e: SnippetViewResult) => {
state.callbacks.forEach((cb) => void cb(e))
Expand Down
28 changes: 21 additions & 7 deletions src/preview/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const logger = lw.log('Server')
export {
getPort,
getUrl,
setHandler,
initialize,
// initialized
}
Expand Down Expand Up @@ -52,9 +53,11 @@ const state: {
httpServer: http.Server,
wsServer?: WsServer,
address?: AddressInfo,
validOriginUri?: vscode.Uri
validOriginUri?: vscode.Uri,
handlers: ((url: string) => string | undefined)[]
} = {
httpServer: initialize(),
handlers: []
// initialized
}

Expand All @@ -76,6 +79,10 @@ async function getUrl(pdfUri: vscode.Uri): Promise<{url: string, uri: vscode.Uri
return { url, uri: vscode.Uri.parse(url, true) }
}

function setHandler(newHandler: (url: string) => string | undefined) {
state.handlers.push(newHandler)
}

function getValidOrigin(): string {
if (state.validOriginUri) {
return `${state.validOriginUri.scheme}://${state.validOriginUri.authority}`
Expand Down Expand Up @@ -144,7 +151,7 @@ function checkHttpOrigin(req: http.IncomingMessage, response: http.ServerRespons
return true
}
const reqOrigin = req.headers['origin']
if (reqOrigin !== undefined && reqOrigin !== validOrigin) {
if (reqOrigin !== undefined && !reqOrigin.startsWith('vscode-webview:') && reqOrigin !== validOrigin) {
logger.log(`Origin in http request is invalid: ${JSON.stringify(req.headers)}`)
logger.log(`Valid origin: ${validOrigin}`)
response.writeHead(403)
Expand All @@ -155,7 +162,7 @@ function checkHttpOrigin(req: http.IncomingMessage, response: http.ServerRespons
}
}

function sendOkResponse(response: http.ServerResponse, content: Buffer, contentType: string) {
function sendOkResponse(response: http.ServerResponse, content: Buffer, contentType: string, cors: boolean = true) {
//
// Headers to enable site isolation.
// - https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header
Expand All @@ -170,7 +177,7 @@ function sendOkResponse(response: http.ServerResponse, content: Buffer, contentT
response.writeHead(200, {
'Content-Type': contentType,
'Content-Length': content.length,
...sameOriginPolicyHeaders
...(cors ? sameOriginPolicyHeaders : {'Access-Control-Allow-Origin': '*'})
})
response.end(content)
}
Expand Down Expand Up @@ -209,13 +216,20 @@ async function handler(request: http.IncomingMessage, response: http.ServerRespo
}
let root: string
if (request.url.startsWith('/build/') || request.url.startsWith('/cmaps/') || request.url.startsWith('/standard_fonts/')) {
root = path.resolve(`${lw.extensionRoot}/node_modules/pdfjs-dist`)
root = path.resolve(lw.extensionRoot, 'node_modules', 'pdfjs-dist')
} else if (request.url.startsWith('/out/viewer/') || request.url.startsWith('/viewer/')) {
// For requests to /out/viewer/*.js and requests to /viewer/*.ts.
// The latter is for debugging with sourcemap.
root = path.resolve(lw.extensionRoot)
} else {
root = path.resolve(`${lw.extensionRoot}/viewer`)
root = path.resolve(lw.extensionRoot, 'viewer')
}
for (const overrideHandler of state.handlers) {
const overrideRoot = overrideHandler(request.url)
if (overrideRoot !== undefined) {
root = overrideRoot
break
}
}
//
// Prevent directory traversal attack.
Expand Down Expand Up @@ -276,7 +290,7 @@ async function handler(request: http.IncomingMessage, response: http.ServerRespo
}
response.end()
} else {
sendOkResponse(response, content, contentType)
sendOkResponse(response, content, contentType, false)
}
})
}
Expand Down
21 changes: 0 additions & 21 deletions src/utils/webview.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,4 @@
import * as vscode from 'vscode'
import { lw } from '../lw'

const logger = lw.log('Util', 'Webview')

let pathLogged = false
export function replaceWebviewPlaceholders(content: string, webview: vscode.Webview): string {
const extensionRootUri = vscode.Uri.file(lw.extensionRoot)
const resourcesFolderUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionRootUri, 'resources'))
const resourcesFolderLink = resourcesFolderUri.toString()
const pdfjsDistUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionRootUri, 'node_modules', 'pdfjs-dist'))
const pdfjsDistLink = pdfjsDistUri.toString()
if (!pathLogged) {
pathLogged = true
logger.log(`%VSCODE_RES% = ${resourcesFolderLink} .`)
logger.log(`%VSCODE_PDFJS_DIST% = ${pdfjsDistLink} .`)
logger.log(`%VSCODE_CSP% = ${webview.cspSource} .`)
}
return content.replace(/%VSCODE_RES%/g, resourcesFolderLink)
.replace(/%VSCODE_PDFJS_DIST%/g, pdfjsDistLink)
.replace(/%VSCODE_CSP%/g, webview.cspSource)
}

function getMoveCommands(tabEditorGroup: string) {
if (tabEditorGroup === 'left') {
Expand Down

3 comments on commit e4e48b1

@benz0li
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@James-Yu Regarding #4158 (comment):

[Warning] [blocked] The page at https://coder.jupyter.b-data.ch/user/benz0li/code-server/stable-853ab407deb63558f9971fd44dfe04d21ee81588/static/out/vs/workbench/contrib/webview/browser/pre/index.html?id=d1dc578a-4c9a-449a-8a36-5a052dc3f646&origin=4c791e7e-5d8a-4b63-bce3-0e9ab51ae3e4&swVersion=4&extensionId=James-Yu.latex-workshop&platform=browser&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=https%3A%2F%2Fcoder.jupyter.b-data.ch&remoteAuthority=coder.jupyter.b-data.ch&purpose=webviewView was not allowed to run insecure content from http://127.0.0.1:41493/snippetview/snippetview.js. (index.html, line 1009)

[Warning] [blocked] The page at https://coder.jupyter.b-data.ch/user/benz0li/code-server/stable-853ab407deb63558f9971fd44dfe04d21ee81588/static/out/vs/workbench/contrib/webview/browser/pre/index.html?id=d1dc578a-4c9a-449a-8a36-5a052dc3f646&origin=4c791e7e-5d8a-4b63-bce3-0e9ab51ae3e4&swVersion=4&extensionId=James-Yu.latex-workshop&platform=browser&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=https%3A%2F%2Fcoder.jupyter.b-data.ch&remoteAuthority=coder.jupyter.b-data.ch&purpose=webviewView was not allowed to run insecure content from http://127.0.0.1:41493/build/pdf.mjs. (index.html, line 1009)

[Warning] [blocked] The page at https://coder.jupyter.b-data.ch/user/benz0li/code-server/stable-853ab407deb63558f9971fd44dfe04d21ee81588/static/out/vs/workbench/contrib/webview/browser/pre/index.html?id=d1dc578a-4c9a-449a-8a36-5a052dc3f646&origin=4c791e7e-5d8a-4b63-bce3-0e9ab51ae3e4&swVersion=4&extensionId=James-Yu.latex-workshop&platform=browser&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=https%3A%2F%2Fcoder.jupyter.b-data.ch&remoteAuthority=coder.jupyter.b-data.ch&purpose=webviewView was not allowed to run insecure content from http://127.0.0.1:41493/snippetview/pdfrenderer.js. (index.html, line 1009)

[Warning] [blocked] The page at https://coder.jupyter.b-data.ch/user/benz0li/code-server/stable-853ab407deb63558f9971fd44dfe04d21ee81588/static/out/vs/workbench/contrib/webview/browser/pre/index.html?id=d1dc578a-4c9a-449a-8a36-5a052dc3f646&origin=4c791e7e-5d8a-4b63-bce3-0e9ab51ae3e4&swVersion=4&extensionId=James-Yu.latex-workshop&platform=browser&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=https%3A%2F%2Fcoder.jupyter.b-data.ch&remoteAuthority=coder.jupyter.b-data.ch&purpose=webviewView was not allowed to run insecure content from http://127.0.0.1:41493/snippetview/snippetview.css. (index.html, line 1009)

@James-Yu
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The extension need to read data from the created http server for pdf viewing and (newly added) snippet rendering. The server is hosted at 127.0.0.1:random. I’m not sure how that is interpreted in code-server.

127.0.0.1 is also allowed in the cors of snippet panel. This is another thing that code-server need to deal with if the server itself now is hosted remotely.

@benz0li
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #3639, @modaresimr has shown a more generic approach to get it also working with code-server.

@modaresimr Can you please assist @James-Yu a hand on this? Thank you.

Please sign in to comment.