# CSP (Content-Security-Policy) Vite Plugin

<!-- cspell: disable bracketsstartstop -->

[![version](https://img.shields.io/github/v/tag/josh-hemphill/vite-plugin-csp?sort=semver&style=flat-square)](https://github.com/josh-hemphill/vite-plugin-csp/releases)
[![NPM](https://img.shields.io/static/v1?label=&message=NPM&color=informational&style=flat-square)](https://npmjs.org/package/vite-plugin-csp)
[![Codecov](https://img.shields.io/codecov/c/github/josh-hemphill/vite-plugin-csp.svg?style=flat-square)](https://codecov.io/gh/josh-hemphill/vite-plugin-csp)
[![Libraries.io dependency status for latest release](https://img.shields.io/librariesio/release/npm/vite-plugin-csp?label=Deps&style=flat-square)](https://libraries.io/npm/vite-plugin-csp)
[![Rate on Openbase](https://badges.openbase.io/js/rating/vite-plugin-csp.svg)](https://openbase.io/js/vite-plugin-csp?utm_source=embedded&utm_medium=badge&utm_campaign=rate-badge)
[![Test](https://github.com/josh-hemphill/vite-plugin-csp/actions/workflows/test.yml/badge.svg)](https://github.com/josh-hemphill/vite-plugin-csp/actions/workflows/test.yml)
[![Release](https://github.com/josh-hemphill/vite-plugin-csp/actions/workflows/release.yml/badge.svg)](https://github.com/josh-hemphill/vite-plugin-csp/actions/workflows/release.yml)

Leverages [csp-typed-directives](https://github.com/josh-hemphill/csp-typed-directives) to create typed CSP `<meta>` policies and validated interdependant headers.
e.g. the CSP, CSP Report-Only, Report-To, and Referrer-Policy headers.

Mostly config compatible with [csp-html-webpack-plugin](https://github.com/slackhq/csp-html-webpack-plugin)

## WARNING, STILL EARLY AND THINGS LIKE MODULE RESOLUTION ARE FINICKY

### Now looking at making a multi-repo because this is going to require multiple layers of shared functionality and also built to an unplugin

## Installation

Install the plugin with npm:

```shell
$ npm install --save-dev vite-plugin-csp
# Or shorthand
npm i -D vite-plugin-csp
```

## Known issues

  - Relative modules are resolved relative to the CWD, not the file
  - no SSR support (and thus no nonce support)
  - No parsing of JS embeded sources (since that would require framework specific plugins)
  - Only `script` and `style` related directives are supported (except for the inclusion of `report-to` for generating headers)

## Under construction :)

<!-- 
## Zero Config Usage

Add your base logo as `logo.png` file to your assets folder.

Add the plugin to your vite config as follows:

```javascript
const ViteCspPlugin = require('vite-plugin-csp')
// or ESM
import { ViteCspPlugin } from "module";

plugins: [
  ViteCspPlugin()
]
```

## Basic Usage <!-- [<svg alt="codesandbox" xmlns="http://www.w3.org/2000/svg" width="16" height="18"><path d="M7.219 15.877V9.394l-5.73-3.208v3.696l2.624 1.48v2.78l3.106 1.735zm1.488.038l3.163-1.773v-2.845l2.642-1.49V6.16l-5.805 3.26v6.496zm5.041-11l-3.05-1.72-2.68 1.512L5.32 3.193 2.241 4.937l5.744 3.215 5.763-3.237zM0 13.513V4.53L8 0l8 4.511V13.5l-8.001 4.484L0 13.513z" fill="currentColor"/></svg>](https://codesandbox.io/s/vite-plugin-csp-demo-uh195?file=/webpack.config.js) -->
<!-- 
Add the plugin to your vite config as follows:

```javascript
const ViteCspPlugin = require('vite-plugin-csp')
// or ESM
import { ViteCspPlugin } from "module";

...

plugins: [
  ViteCspPlugin('/path/to/logo.png') // svg works too!
]
```

The default configuration will automatically generate webapp manifest files along with
[44 different icon formats](https://github.com/josh-hemphill/vite-plugin-csp/tree/master/test/fixtures/expected/default)
as appropriate for iOS devices, Android devices, Windows Phone and various desktop browsers out of your single `logo.png`.

> **Tip:** You might want to [fine tune](#advanced-usage) what vendors to support.

### A Note on Path Resolution

Under the hood, Vite/Rollup resolve the paths to the logo and favicons according to the following
rules:

  * If `/path/to/logo` is absolute, there is nothing to resolve and the path
specified is used as is.

  * If `./path/to/logo` is relative, it's resolved with respect to `process.cwd()`.

### HTML Injection

In combination with [Vite's html plugin hooks](https://vitejs.dev/guide/api-plugin.html#transformindexhtml) it will also inject the necessary html for you:

```html
<link rel="apple-touch-icon" sizes="57x57" href="/assets/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/assets/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/assets/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/assets/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/assets/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/assets/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="167x167" href="/assets/apple-touch-icon-167x167.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon-180x180.png">
<link rel="apple-touch-icon" sizes="1024x1024" href="/assets/apple-touch-icon-1024x1024.png">
<link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 1)" href="/assets/apple-touch-startup-image-320x460.png">
<link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 2)" href="/assets/apple-touch-startup-image-640x920.png">
<link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" href="/assets/apple-touch-startup-image-640x1096.png">
<link rel="apple-touch-startup-image" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" href="/assets/apple-touch-startup-image-750x1294.png">
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 736px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 3)" href="/assets/apple-touch-startup-image-1182x2208.png">
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 736px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 3)" href="/assets/apple-touch-startup-image-1242x2148.png">
<link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 1)" href="/assets/apple-touch-startup-image-748x1024.png">
<link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 2)" href="/assets/apple-touch-startup-image-1496x2048.png">
<link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 1)" href="/assets/apple-touch-startup-image-768x1004.png">
<link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 2)" href="/assets/apple-touch-startup-image-1536x2008.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="228x228" href="/assets/coast-228x228.png">
<link rel="manifest" href="/assets/manifest.json">
<link rel="shortcut icon" href="/assets/favicon.ico">
<link rel="yandex-tableau-widget" href="/assets/yandex-browser-manifest.json">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title">
<meta name="application-name">
<meta name="mobile-web-app-capable" content="yes">
<meta name="msapplication-TileColor" content="#fff">
<meta name="msapplication-TileImage" content="/assets/mstile-144x144.png">
<meta name="msapplication-config" content="/assets/browserconfig.xml">
<meta name="theme-color" content="#fff">
```

## Advanced Usage

```javascript
plugins: [
  ViteCspPlugin({
    /** Your source logo (Will default to ) */
    logo?: "assets/logo.png",
    /** Inject html links/metadata. */
    inject?: true,
    /** `Favicons` configuration options
    *  - [See `favicons` documentation](https://github.com/itgalaxy/favicons) */
    favicons?: FaviconsConfig,
    /** The root of the project from which you want to load metadata */
    projectRoot?: process.cwd(),

    /** prefix is delegated to Rollup/Vite (keeping for people migrating from Webpack)
    * @deprecated */
    prefix?: string,
    /** Caching is delegated to Rollup/Vite (keeping for people migrating from Webpack)
    * @deprecated */
    cache?: boolean,
    /** Public Path is delegated to Rollup/Vite (keeping for people migrating from Webpack)
    * @deprecated */
    publicPath?: string,
    /** Output Path is delegated to Rollup/Vite (keeping for people migrating from Webpack)
    * @deprecated */
    outputPath?: string,
  })
]
```

To fine tune what icons/metadata is generated, refer to
[favicons' documentation](https://github.com/haydenbleasel/favicons#usage).

The options specified under `favicons:` are handed over as is to [favicons],
except that if `appName`, `appDescription`, `version`, `developerName` or
`developerURL` are left `undefined`, they will be automatically inferred
respectively from `name`, `description`, `version`, `author.name` and
`author.url` as defined in the nearest `package.json` if available.
And if there's no `author` it will use the first in the `contributors`.
To disable automatically retrieving metadata from `package.json`, simply set
to `null` the properties you want to omit.

### Examples

#### Basic

```javascript
const ViteCspPlugin = require('vite-plugin-csp')
// or ESM
import { ViteCspPlugin } from "module";

plugins: [
  ViteCspPlugin({
    logo: './src/logo.png', // svg works too!
    favicons: {
      appName: 'my-app',
      appDescription: 'My awesome App',
      developerName: 'Me',
      developerURL: null, // prevent retrieving from the nearest package.json
      background: '#ddd',
      theme_color: '#333',
      icons: {
        coast: false,
        yandex: false
      }
    }
  })
]
```

To fine tune what icons/metadata is generated, refer to
[favicons' documentation](https://github.com/haydenbleasel/favicons#usage).

#### Handling Multiple HTML Files

Vite calls the HTML transform hook for each HTML file template file you have configured in Vite, so this works automatically.

## Changelog

Take a look at the [CHANGELOG.md](https://github.com/josh-hemphill/vite-plugin-csp/tree/latest/CHANGELOG.md).

## Contribution

You're free to contribute to this project by submitting [issues](https://github.com/josh-hemphill/vite-plugin-csp/issues) and/or [pull requests](https://github.com/josh-hemphill/vite-plugin-csp/pulls).

Please keep in mind that every change and feature should be covered by
tests.

## License

This project is licensed under [MIT](https://github.com/josh-hemphill/vite-plugin-csp/blob/latest/LICENSE).

[favicons]: https://github.com/haydenbleasel/favicons

## Contributors
 -->
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
