vuejs / vitepress

Vite & Vue powered static site generator.
https://vitepress.dev
MIT License
13.31k stars 2.15k forks source link

Content Security Policy: unsafe-eval has to be set due to `new Function` call when using customized search #3685

Open snowbagoly opened 8 months ago

snowbagoly commented 8 months ago

Describe the bug

We have set the Content Security Policy not to allow unsafe-eval. This worked until we added a custom tokenize function for the search. Now the page fails to load the scripts with this error, which results in broken navigation:

Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' {... generated sha256 of all script blocks on the page ...}".

    at new Function (<anonymous>)
    at deserializeFunctions (index.html:29:12475)
    at index.html:29:12397
    at Array.reduce (<anonymous>)
    at deserializeFunctions (index.html:29:12377)
    at index.html:29:12397
    at Array.reduce (<anonymous>)
    at deserializeFunctions (index.html:29:12377)
    at index.html:29:12397
    at Array.reduce (<anonymous>)

The stacktrace points to the new Function call in deserializeFunctions (https://github.com/vuejs/vitepress/blob/main/src/node/utils/fnSerialize.ts#L42).

Reproduction

To reproduce the issue, you have to create a vitepress config file that defines at least one function. In our case, we have defined a custom tokenize function for the search:

export default defineConfig({
  // ...
  themeConfig: {
    search: {
      provider: "local",
      options: {
        miniSearch: {
          options: {
            // Overriding the default regex (/[\n\r\p{Z}\p{P}]/u), to include e.g. "C#" as a token
            tokenize: (text, fieldName) => text.split(/[\n\r\p{Z}\p{Terminal_Punctuation}]/u),
          }
        }
      }
    }
    // ...
  }
});

Also you have to set the Content Security Policy not to allow unsafe-eval, e.g. if you use a similar configuration to us, you have to set the script-src to include self, and an sha256 for each script block.

Expected behavior

Vitepress docs work with the customized search, even if the CSP does not allow unsafe-eval.

System Info

System:
    OS: macOS 14.2.1
    CPU: (12) arm64 Apple M2 Max
    Memory: 1.62 GB / 64.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.19.1 - /opt/homebrew/opt/node@18/bin/node
    npm: 10.2.4 - /opt/homebrew/opt/node@18/bin/npm
    pnpm: 8.14.1 - /opt/homebrew/bin/pnpm
  Browsers:
    Chrome: 123.0.6312.59
    Safari: 17.2.1
  npmPackages:
    vitepress: 1.0.0-rc.44 => 1.0.0-rc.44

Additional context

No response

Validations

brc-dd commented 8 months ago

How would it work then?

snowbagoly commented 8 months ago

Thanks for looking into this! As far as I understood from other similar issues, they usually add a precompile step, resulting in directly adding the relevant functions, instead of serializing it and then deserializing it from a string. Would this be possible?

brc-dd commented 8 months ago

Ah good idea. We can do that.