From 3a953746f7ca990912606991d3fa675f36370cfc Mon Sep 17 00:00:00 2001 From: abose Date: Wed, 13 May 2026 17:20:31 +0530 Subject: [PATCH] fix(electron): allow cross-origin XHR/fetch to asset:// scheme The asset:// scheme was registered with only supportFetchAPI+stream, which caused Chromium to block XHR/fetch from the phtauri://localhost app origin to asset://localhost/... with a CORS error. Extensions loaded from appLocalData/assets/ failed to load their requirejs-config, keymap, snippets, and HTML panels. Add standard+secure+corsEnabled to the scheme privileges (matching phtauri and Tauri's wry asset protocol) and set Access-Control-Allow-Origin:* on responses so cross-origin reads from the app are allowed. --- src-electron/main.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src-electron/main.js b/src-electron/main.js index 29a2da4..3b537eb 100644 --- a/src-electron/main.js +++ b/src-electron/main.js @@ -40,11 +40,17 @@ protocol.registerSchemesAsPrivileged([ } }, { - // asset:// is for serving static files only - minimal privileges to match Tauri's security posture - // No standard/secure/corsEnabled - just enough for fetch() to read local assets + // asset:// serves static files (extensions, themes, user assets) from appLocalData/assets/. + // Needs standard+secure+corsEnabled so the phtauri:// app origin can XHR/fetch these files + // (RequireJS text plugin, $.getJSON for requirejs-config.json/keymap.json/snippets.json, etc.). + // Without these privileges Chromium blocks cross-origin requests to asset:// with a CORS error. + // This matches Tauri's wry asset protocol, which is also CORS-enabled. scheme: 'asset', privileges: { + standard: true, + secure: true, supportFetchAPI: true, + corsEnabled: true, stream: true } } @@ -326,7 +332,7 @@ app.whenReady().then(async () => { const appDataDir = getAppDataDir(); const assetsDir = path.join(appDataDir, 'assets'); - protocol.handle('asset', (request) => { + protocol.handle('asset', async (request) => { try { const url = new URL(request.url); // Decode the path from URL encoding @@ -341,13 +347,17 @@ app.whenReady().then(async () => { // Security: Ensure path is under assets directory (prevent directory traversal) if (!normalizedRequested.startsWith(normalizedAssetsDir)) { console.error('Asset access denied - path not under assets dir:', requestedPath); - return new Response('Access denied', { status: 403 }); + return new Response('Access denied', { status: 403, headers: { 'Access-Control-Allow-Origin': '*' } }); } - return net.fetch(`file://${normalizedRequested}`); + const response = await net.fetch(`file://${normalizedRequested}`); + // Mirror Tauri's wry asset protocol: allow the phtauri:// app origin to XHR/fetch these files. + const headers = new Headers(response.headers); + headers.set('Access-Control-Allow-Origin', '*'); + return new Response(response.body, { status: response.status, statusText: response.statusText, headers }); } catch (err) { console.error('Asset protocol error:', err); - return new Response('Not found', { status: 404 }); + return new Response('Not found', { status: 404, headers: { 'Access-Control-Allow-Origin': '*' } }); } });