improve url origin checking in shim

This commit is contained in:
Nystik
2026-06-02 17:09:54 +02:00
parent 3833ef2668
commit caaf6b3144
4 changed files with 22 additions and 8 deletions

View File

@@ -7,7 +7,13 @@ function normalize(p) {
const virtualFiles = new Map(); const virtualFiles = new Map();
export function setVirtualFile(path, content) { 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) { export function removeVirtualFile(path) {

View File

@@ -138,7 +138,7 @@ function base64ToArrayBuffer(base64) {
return bytes.buffer; return bytes.buffer;
} }
function isSameOrigin(url) { export function isSameOrigin(url) {
if ( if (
!url || !url ||
url.startsWith("/") || url.startsWith("/") ||

View File

@@ -1,6 +1,8 @@
// Override window.requestUrl to proxy external requests through our server, bypassing CORS. // 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. // Obsidian sets window.requestUrl in app.js, so we override it after app.js loads.
import { isSameOrigin } from "./globals.js";
function base64ToArrayBuffer(base64) { function base64ToArrayBuffer(base64) {
const binary = atob(base64); const binary = atob(base64);
const bytes = new Uint8Array(binary.length); const bytes = new Uint8Array(binary.length);
@@ -29,12 +31,8 @@ async function proxyRequestUrl(request) {
request = { url: request }; request = { url: request };
} }
const isSameOrigin = // Same-origin requests don't need the proxy.
request.url.startsWith(window.location.origin) || if (isSameOrigin(request.url)) {
request.url.startsWith("/");
// Same-origin requests don't need the proxy
if (isSameOrigin) {
const res = await fetch(request.url, { const res = await fetch(request.url, {
method: request.method || "GET", method: request.method || "GET",
headers: request.headers || {}, headers: request.headers || {},

View File

@@ -104,6 +104,12 @@ export async function extractObsidianModule() {
return captured; 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. // Serialize per-id load/unload so rapid toggles can't race.
const inFlight = new Map(); const inFlight = new Map();
@@ -128,7 +134,11 @@ export function loadVirtualPlugin(entry) {
return; return;
} }
assertSameOrigin(entry.scriptUrl);
if (entry.cssUrl) { if (entry.cssUrl) {
assertSameOrigin(entry.cssUrl);
const link = document.createElement("link"); const link = document.createElement("link");
link.rel = "stylesheet"; link.rel = "stylesheet";
link.href = entry.cssUrl; link.href = entry.cssUrl;