Skip to content

Commit

Permalink
feat!: make DOMPurify as optional (#335)
Browse files Browse the repository at this point in the history
- replace `isomorphic-dompurify` with `dompurify` and make it a dev deps
  • Loading branch information
ghiscoding authored May 7, 2024
1 parent da29dd1 commit 41c1c2f
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 119 deletions.
3 changes: 0 additions & 3 deletions docs/column-functionalities/editors.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,9 +368,6 @@ const columnDefinitions = [
];
```
### Change Default DOMPurify Options (sanitize html)
If you find that the HTML that you passed is being sanitized and you wish to change it, then you can change the default `sanitizeHtmlOptions` property defined in the Global Grid Options, for more info on how to change these global options, see the [Docs - Global Grid Options](../grid-functionalities/global-options.md) and also take a look at the [GitHub - DOMPurify](https://github.com/cure53/DOMPurify#can-i-configure-it) configurations.
## Editor Options
#### Column Editor `editorOptions`
Expand Down
3 changes: 0 additions & 3 deletions docs/column-functionalities/editors/select-dropdown-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,3 @@ this.columnDefinitions = [
}
];
```
### Change Default DOMPurify Options (sanitize html)
If you find that the HTML that you passed is being sanitized and you wish to change it, then you can change the default `sanitizeHtmlOptions` property defined in the Global Grid Options, for more info on how to change these global options, see the `Global Grid Options` and also take a look at the [GitHub - DOMPurify](https://github.com/cure53/DOMPurify#can-i-configure-it) configurations.
4 changes: 0 additions & 4 deletions docs/column-functionalities/filters/select-filter.md
Original file line number Diff line number Diff line change
Expand Up @@ -426,10 +426,6 @@ this.columnDefinitions = [
];
```

#### Change Default DOMPurify Options (sanitize html)
If you find that the HTML that you passed is being sanitized and you wish to change it, then you can change the default `sanitizeHtmlOptions` property defined in the Global Grid Options, for more info on how to change these global options, see the [Wiki - Global Grid Options](../../grid-functionalities/Global-Options.md) and also take a look at the [GitHub - DOMPurify](https://github.com/cure53/DOMPurify#can-i-configure-it) configurations.


### Collection Add Blank Entry
In some cases a blank entry at the beginning of the collection could be useful, the most common example for this is to use the first option as a blank entry to tell our Filter to show everything. So for that we can use the `addBlankEntry` flag in `collectionOptions
Expand Down
2 changes: 1 addition & 1 deletion docs/column-functionalities/formatters.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ Since version 4.x, you can now also return native DOM element instead of an HTML
2. Performance (the reasons are similar to point 1.)
- since it's native it can be appended directly to the grid cell
- when it's an HTML string, it has to do 2 extra steps (which is an overhead process)
i. sanitize the string (we use [DOMPurify](https://github.com/cure53/DOMPurify) by default)
i. sanitize the string (when a sanitizer, for example [DOMPurify](https://github.com/cure53/DOMPurify))
ii. SlickGrid then has to convert it to native element by using `innerHTML` on the grid cell

Demo
Expand Down
39 changes: 23 additions & 16 deletions docs/developer-guides/csp-compliance.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
## CSP Compliance
The library is now, at least mostly, CSP (Content Security Policy) compliant since `v4.0`, however there are some exceptions to be aware of. When using any html string as template (for example with Custom Formatter returning an html string), you will not be fully compliant unless you return `TrustedHTML`. You can achieve this by using the `sanitizer` method in combo with [DOMPurify](https://github.com/cure53/DOMPurify) to return `TrustedHTML` as shown below and with that in place you should be CSP compliant.
The library is for the most part CSP (Content Security Policy) compliant since `v4.0` **but** only if you configure the `sanitizer` grid option. We were previously using `DOMPurify` internally in the project (in version <=4.x) but it was made optional in version 5 and higher. The main reason to make it optional was because most users would use `dompurify` but some users who require SSR support would want to use `isomorphic-dompurify`. You could also skip the `sanitizer` configuration, but that is not recommended.

> **Note** the default sanitizer in Slickgrid-Universal is actually already configured to return `TrustedHTML` but the CSP safe in the DataView is opt-in via `useCSPSafeFilter`
> **Note** even if the `sanitizer` is optional, we **strongly suggest** that you configure it as a global grid option to avoid possible XSS attacks from your data and also to be CSP compliant. Note that for Salesforce users, you do not have to configure it since Salesforce already use DOMPurify internally.
```typescript
import DOMPurify from 'dompurify';
import { GridOption } from 'slickgrid-react';
As mentioned above, the project is mostly CSP compliant, however there are some exceptions to be aware of. When using any html string as template (for example with Custom Formatter returning an html string), you will not be fully compliant unless you return `TrustedHTML`. You can achieve this by using the `sanitizer` method in combo with [DOMPurify](https://github.com/cure53/DOMPurify) to return `TrustedHTML` as shown below and with that in place you should be CSP compliant.

export class Example1 {
gridOptions: GridOption;
```ts
// prefer the global grid options if possible
this.gridOptions = {
sanitizer: (dirtyHtml) => DOMPurify.sanitize(dirtyHtml, { ADD_ATTR: ['level'], RETURN_TRUSTED_TYPE: true })
};
```

prepareGrid() {
// ...
> **Note** If you're wondering about the `ADD_ATTR: ['level']`, well the "level" is a custom attribute used by SlickGrid Grouping/Draggable Grouping to track the grouping level depth and it must be kept.
this.gridOptions = {
// NOTE: DOM Purify is already configured in Slickgrid-Universal with the configuration shown below
sanitizer: (html) => DOMPurify.sanitize(html, { RETURN_TRUSTED_TYPE: true }),
// you could also optionally use the sanitizerOptions instead
// sanitizerOptions: { RETURN_TRUSTED_TYPE: true }
}
}
> **Note** the DataView is not CSP safe by default, it is opt-in via the `useCSPSafeFilter` option.
```typescript
import DOMPurify from 'dompurify';
import { Slicker, SlickVanillaGridBundle } from '@slickgrid-universal/vanilla-bundle';

// DOM Purify is already configured in Slickgrid-Universal with the configuration shown below
this.gridOptions = {
sanitizer: (html) => DOMPurify.sanitize(html, { RETURN_TRUSTED_TYPE: true }),
// you could also optionally use the sanitizerOptions instead
// sanitizerOptions: { RETURN_TRUSTED_TYPE: true }
}
this.sgb = new Slicker.GridBundle(gridContainerElm, this.columnDefinitions, this.gridOptions, this.dataset);
```

with this code in place, we can use the following CSP meta tag (which is what we use in the lib demo, ref: [index.html](https://github.com/ghiscoding/slickgrid-universal/blob/master/examples/vite-demo-vanilla-bundle/index.html#L8-L14))
```html
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'nonce-random-string'; require-trusted-types-for 'script'; trusted-types dompurify">
Expand Down
26 changes: 13 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@
"/src/slickgrid-react"
],
"dependencies": {
"@slickgrid-universal/common": "~5.0.0-beta.1",
"@slickgrid-universal/custom-footer-component": "~5.0.0-beta.1",
"@slickgrid-universal/empty-warning-component": "~5.0.0-beta.1",
"@slickgrid-universal/event-pub-sub": "~5.0.0-beta.1",
"@slickgrid-universal/pagination-component": "~5.0.0-beta.1",
"@slickgrid-universal/common": "~5.0.0-beta.2",
"@slickgrid-universal/custom-footer-component": "~5.0.0-beta.2",
"@slickgrid-universal/empty-warning-component": "~5.0.0-beta.2",
"@slickgrid-universal/event-pub-sub": "~5.0.0-beta.2",
"@slickgrid-universal/pagination-component": "~5.0.0-beta.2",
"dequal": "^2.0.3",
"font-awesome": "^4.7.0",
"i18next": "^23.11.2",
Expand All @@ -107,13 +107,13 @@
"@formkit/tempo": "^0.1.1",
"@popperjs/core": "^2.11.8",
"@release-it/conventional-changelog": "^8.0.1",
"@slickgrid-universal/composite-editor-component": "~5.0.0-beta.1",
"@slickgrid-universal/custom-tooltip-plugin": "~5.0.0-beta.1",
"@slickgrid-universal/excel-export": "~5.0.0-beta.1",
"@slickgrid-universal/graphql": "~5.0.0-beta.1",
"@slickgrid-universal/odata": "~5.0.0-beta.1",
"@slickgrid-universal/rxjs-observable": "~5.0.0-beta.1",
"@slickgrid-universal/text-export": "~5.0.0-beta.1",
"@slickgrid-universal/composite-editor-component": "~5.0.0-beta.2",
"@slickgrid-universal/custom-tooltip-plugin": "~5.0.0-beta.2",
"@slickgrid-universal/excel-export": "~5.0.0-beta.2",
"@slickgrid-universal/graphql": "~5.0.0-beta.2",
"@slickgrid-universal/odata": "~5.0.0-beta.2",
"@slickgrid-universal/rxjs-observable": "~5.0.0-beta.2",
"@slickgrid-universal/text-export": "~5.0.0-beta.2",
"@types/dompurify": "^3.0.5",
"@types/fnando__sparkline": "^0.3.7",
"@types/i18next-xhr-backend": "^1.4.2",
Expand All @@ -134,7 +134,7 @@
"custom-event-polyfill": "^1.0.7",
"cypress": "^13.8.1",
"cypress-real-events": "^1.12.0",
"cypress": "^13.8.1",
"dompurify": "^3.1.2",
"esbuild-loader": "^4.1.0",
"eslint": "^9.1.1",
"eslint-plugin-cypress": "^3.0.2",
Expand Down
2 changes: 2 additions & 0 deletions src/examples/slickgrid/Example2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
GridOption,
SlickgridReact,
} from '../../slickgrid-react';
import DOMPurify from 'dompurify';
import React from 'react';
import BaseSlickGridState from './state-slick-grid-base';

Expand Down Expand Up @@ -114,6 +115,7 @@ export default class Example2 extends React.Component<Props, State> {
hideTotalItemCount: true,
hideLastUpdateTimestamp: true
},
sanitizer: (dirtyHtml) => DOMPurify.sanitize(dirtyHtml, { ADD_ATTR: ['level'], RETURN_TRUSTED_TYPE: true }),

// you customize all formatter at once certain options through "formatterOptions" in the Grid Options
// or independently through the column definition "params", the option names are the same
Expand Down
Loading

0 comments on commit 41c1c2f

Please sign in to comment.