diff --git a/packages/shim/src/fs/virtual-files.js b/packages/shim/src/fs/virtual-files.js index 65078f0..121e6e7 100644 --- a/packages/shim/src/fs/virtual-files.js +++ b/packages/shim/src/fs/virtual-files.js @@ -7,7 +7,13 @@ function normalize(p) { const virtualFiles = new Map(); export function setVirtualFile(path, content) { - virtualFiles.set(normalize(path), content); + const normalized = normalize(path); + + if (normalized.split("/").includes("..")) { + throw new Error(`virtual file path may not contain '..': ${path}`); + } + + virtualFiles.set(normalized, content); } export function removeVirtualFile(path) { diff --git a/packages/shim/src/globals.js b/packages/shim/src/globals.js index fac08e8..c829d7e 100644 --- a/packages/shim/src/globals.js +++ b/packages/shim/src/globals.js @@ -138,7 +138,7 @@ function base64ToArrayBuffer(base64) { return bytes.buffer; } -function isSameOrigin(url) { +export function isSameOrigin(url) { if ( !url || url.startsWith("/") || diff --git a/packages/shim/src/request-url.js b/packages/shim/src/request-url.js index b67b025..8a43b6e 100644 --- a/packages/shim/src/request-url.js +++ b/packages/shim/src/request-url.js @@ -1,6 +1,8 @@ // Override window.requestUrl to proxy external requests through our server, bypassing CORS. // Obsidian sets window.requestUrl in app.js, so we override it after app.js loads. +import { isSameOrigin } from "./globals.js"; + function base64ToArrayBuffer(base64) { const binary = atob(base64); const bytes = new Uint8Array(binary.length); @@ -29,12 +31,8 @@ async function proxyRequestUrl(request) { request = { url: request }; } - const isSameOrigin = - request.url.startsWith(window.location.origin) || - request.url.startsWith("/"); - - // Same-origin requests don't need the proxy - if (isSameOrigin) { + // Same-origin requests don't need the proxy. + if (isSameOrigin(request.url)) { const res = await fetch(request.url, { method: request.method || "GET", headers: request.headers || {}, diff --git a/packages/shim/src/virtual-plugin-loader.js b/packages/shim/src/virtual-plugin-loader.js index f04d09d..884fcca 100644 --- a/packages/shim/src/virtual-plugin-loader.js +++ b/packages/shim/src/virtual-plugin-loader.js @@ -104,6 +104,12 @@ export async function extractObsidianModule() { return captured; } +function assertSameOrigin(url) { + if (new URL(url, location.origin).origin !== location.origin) { + throw new Error(`refusing cross-origin plugin URL: ${url}`); + } +} + // Serialize per-id load/unload so rapid toggles can't race. const inFlight = new Map(); @@ -128,7 +134,11 @@ export function loadVirtualPlugin(entry) { return; } + assertSameOrigin(entry.scriptUrl); + if (entry.cssUrl) { + assertSameOrigin(entry.cssUrl); + const link = document.createElement("link"); link.rel = "stylesheet"; link.href = entry.cssUrl;