|
21 | 21 | */ |
22 | 22 |
|
23 | 23 | import { spawn } from 'node:child_process' |
24 | | -import { error } from 'node:console' |
25 | 24 | import fs from 'node:fs/promises' |
26 | 25 | import path from 'node:path' |
27 | 26 | import { fileURLToPath } from 'node:url' |
@@ -200,16 +199,28 @@ app.get('/corpus/:key/:mode(clean|gitcasso)', async (req, res) => { |
200 | 199 | html = html.replace(regex, `/asset/${key}`) |
201 | 200 | }) |
202 | 201 | if (mode === 'gitcasso') { |
203 | | - html = injectGitcassoScript(key, html) |
| 202 | + html = await injectGitcassoScript(key, html) |
204 | 203 | } |
205 | 204 | return res.send(html) |
206 | 205 | } else if (entry.type === 'html') { |
207 | 206 | // Handle HTML corpus |
208 | 207 | const htmlPath = path.join(__dirname, 'corpus', 'html', `${key}.html`) |
209 | 208 | let html = await fs.readFile(htmlPath, 'utf-8') |
| 209 | + |
| 210 | + // Strip CSP headers that might block our injected scripts |
| 211 | + html = stripCSPFromHTML(html) |
| 212 | + |
210 | 213 | if (mode === 'gitcasso') { |
211 | | - html = injectGitcassoScript(key, html) |
| 214 | + html = await injectGitcassoScript(key, html) |
212 | 215 | } |
| 216 | + |
| 217 | + // Set permissive headers for HTML corpus |
| 218 | + res.set({ |
| 219 | + 'Content-Security-Policy': |
| 220 | + "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob: http: https:;", |
| 221 | + 'X-Content-Type-Options': 'nosniff', |
| 222 | + }) |
| 223 | + |
213 | 224 | return res.send(html) |
214 | 225 | } else { |
215 | 226 | return res.status(400).send('Unknown corpus type') |
@@ -342,43 +353,73 @@ app.listen(PORT, () => { |
342 | 353 | console.log('Click the links to view recorded pages') |
343 | 354 | }) |
344 | 355 |
|
345 | | -function injectGitcassoScript(key: string, html: string) { |
| 356 | +// Strip CSP meta tags and headers from HTML that might block our scripts |
| 357 | +function stripCSPFromHTML(html: string): string { |
| 358 | + // Remove CSP meta tags |
| 359 | + html = html.replace(/<meta[^>]*http-equiv\s*=\s*["']content-security-policy["'][^>]*>/gi, '') |
| 360 | + html = html.replace(/<meta[^>]*name\s*=\s*["']content-security-policy["'][^>]*>/gi, '') |
| 361 | + |
| 362 | + // Remove any other restrictive security meta tags |
| 363 | + html = html.replace(/<meta[^>]*http-equiv\s*=\s*["']x-content-type-options["'][^>]*>/gi, '') |
| 364 | + |
| 365 | + return html |
| 366 | +} |
| 367 | + |
| 368 | +async function injectGitcassoScript(key: string, html: string): Promise<string> { |
346 | 369 | const urlParts = getUrlParts(key) |
347 | 370 |
|
| 371 | + // Read and embed the content script directly to avoid CSP issues |
| 372 | + let contentScriptCode = '' |
| 373 | + try { |
| 374 | + const contentScriptPath = path.join( |
| 375 | + __dirname, |
| 376 | + '..', |
| 377 | + '.output', |
| 378 | + 'chrome-mv3-dev', |
| 379 | + 'content-scripts', |
| 380 | + 'content.js', |
| 381 | + ) |
| 382 | + contentScriptCode = await fs.readFile(contentScriptPath, 'utf-8') |
| 383 | + |
| 384 | + // Patch the content script to remove webextension-polyfill issues |
| 385 | + contentScriptCode = contentScriptCode.replace( |
| 386 | + 'throw new Error("This script should only be loaded in a browser extension.")', |
| 387 | + 'console.warn("Webextension-polyfill check bypassed for corpus testing")', |
| 388 | + ) |
| 389 | + } catch (error) { |
| 390 | + console.warn('Could not read content script, using fallback:', error) |
| 391 | + contentScriptCode = 'console.warn("Content script not found - extension may not be built");' |
| 392 | + } |
| 393 | + |
348 | 394 | // Inject patched content script with location patching |
349 | | - const contentScriptTag = |
350 | | - ` |
| 395 | + const contentScriptTag = ` |
351 | 396 | <script> |
352 | 397 | console.log('Loading Gitcasso with mocked location:', '${urlParts.href}'); |
353 | 398 |
|
354 | | - // Fetch and patch the content script to remove webextension-polyfill issues |
355 | | - fetch('/chrome-mv3-dev/content-scripts/content.js') |
356 | | - .then(response => response.text()) |
357 | | - .then(code => { |
358 | | - console.log('Fetched content script, patching webextension-polyfill and detectLocation...'); |
359 | | -
|
360 | | - // Replace the problematic webextension-polyfill error check |
361 | | - let patchedCode = code.replace( |
362 | | - 'throw new Error("This script should only be loaded in a browser extension.")', |
363 | | - 'console.warn("Webextension-polyfill check bypassed for corpus testing")' |
364 | | - ); |
365 | | - window.gitcassoMockLocation = { |
366 | | - host: '${urlParts.host}', |
367 | | - pathname: '${urlParts.pathname}' |
368 | | - }; |
369 | | -
|
370 | | - // Execute the patched script with browser API mocks prepended |
371 | | - const browserMocks = 'window.chrome=window.chrome||{runtime:{getURL:path=>"chrome-extension://gitcasso-test/"+path,onMessage:{addListener:()=>{}},sendMessage:()=>Promise.resolve(),id:"gitcasso-test"}};window.browser=window.chrome;'; |
372 | | - const script = document.createElement('script'); |
373 | | - script.textContent = browserMocks + patchedCode; |
374 | | - document.head.appendChild(script); |
375 | | - console.log('Gitcasso content script loaded with location patching for:', '` + |
376 | | - urlParts.href + |
377 | | - `'); |
378 | | - }) |
379 | | - .catch(error => { |
380 | | - console.error('Failed to load and patch content script:', error); |
381 | | - }); |
| 399 | + // Set up mocked location |
| 400 | + window.gitcassoMockLocation = { |
| 401 | + host: '${urlParts.host}', |
| 402 | + pathname: '${urlParts.pathname}' |
| 403 | + }; |
| 404 | +
|
| 405 | + // Set up browser API mocks |
| 406 | + window.chrome = window.chrome || { |
| 407 | + runtime: { |
| 408 | + getURL: path => "chrome-extension://gitcasso-test/" + path, |
| 409 | + onMessage: { addListener: () => {} }, |
| 410 | + sendMessage: () => Promise.resolve(), |
| 411 | + id: "gitcasso-test" |
| 412 | + } |
| 413 | + }; |
| 414 | + window.browser = window.chrome; |
| 415 | +
|
| 416 | + // Execute the patched content script directly |
| 417 | + try { |
| 418 | + ${contentScriptCode} |
| 419 | + console.log('Gitcasso content script loaded with location patching for:', '${urlParts.href}'); |
| 420 | + } catch (error) { |
| 421 | + console.error('Failed to execute content script:', error); |
| 422 | + } |
382 | 423 |
|
383 | 424 | // Create floating rebuild button |
384 | 425 | const rebuildButton = document.createElement('div'); |
|
0 commit comments