-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introducing SafeHtml and HtmlDecoder component (#548)
- Loading branch information
1 parent
43e6dc5
commit df3e65c
Showing
11 changed files
with
220 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@headstartwp/core": minor | ||
--- | ||
|
||
Introduces `SafeHtml` and `HtmlDecoder` components. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
--- | ||
slug: /utilities/sanitization | ||
sidebar_label: Escaping & Sanitization | ||
--- | ||
|
||
# Escaping & Sanitization | ||
As you're probably aware, React won't render raw HTML by default. If you want to do so you must use [dangerouslySetInnerHTML](https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html). | ||
|
||
This page describes some of the utility functions and components provided by the framework to help with escaping & sanitization when rendering raw markup. | ||
|
||
## wpKsesPost | ||
|
||
This function sanitizes HTML content with requirements similar to [wp_kses_post](https://developer.wordpress.org/reference/functions/wp_kses_post/). If you are rendering arbitrary HTML markup you should probably run the markup through this function first. | ||
|
||
```jsx | ||
import { wpKsesPost } from '@headstartwp/core'; | ||
|
||
const markup = { __html: wpKsesPost('<p>some raw html</p>') }; | ||
return <div dangerouslySetInnerHTML={markup} />; | ||
``` | ||
|
||
## stripTags | ||
|
||
This function simply strips any html tags from a string. This can be useful in contexts where you don't want any HTML to be rendered. | ||
|
||
```jsx | ||
import { stripTags } from '@headstartwp/core'; | ||
|
||
return <h1>{stripTags('this is a title <span>without a span</span>')}</h1>; | ||
``` | ||
|
||
## BlocksRenderer | ||
|
||
When using [BlocksRenderer](/learn/gutenberg/rendering-blocks) your markup already goes through `wpKsesPost` so there's nothing else you need to worry about. | ||
|
||
## HtmlDecoder | ||
|
||
Sometimes you might just want to decode some HTML entities without actually rendering any HTML tags. For this purpose you can use the `HtmlDecoder` component. | ||
|
||
```jsx | ||
import { HtmlDecoder } from '@headstartwp/core/react'; | ||
|
||
<h1> | ||
<HtmlDecoder html="Hello world! – foo bar –"/> | ||
</h1> | ||
``` | ||
|
||
## SafeHtml | ||
|
||
The `SafeHtml` component provides an easy way to safely render HTML markup. It runs the markup through `wpKsesPost` just like `BlocksRenderer`. | ||
|
||
```jsx | ||
import { SafeHtml } from '@headstartwp/core/react'; | ||
|
||
<SafeHtml html="<div><p>hello world</p> div content</div>"> | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { stripTags } from '../stripTags'; | ||
|
||
describe('stripTags', () => { | ||
test('it strips tags', () => { | ||
expect(stripTags('<div>test</div>')).toBe('test'); | ||
expect(stripTags('<div>test <p>test</p></div>')).toBe('test test'); | ||
expect(stripTags('<div><p><script>alert()</script>hello world</p></div>')).toBe( | ||
'alert()hello world', | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/** | ||
* Utility functions to strip any tags | ||
* | ||
* @param html The html string | ||
* | ||
* @returns | ||
*/ | ||
export function stripTags(html) { | ||
return html.replace(/(<([^>]+)>)/gi, ''); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { FC } from 'react'; | ||
import parse from 'html-react-parser'; | ||
import { stripTags } from '../../dom'; | ||
|
||
export interface HtmlDecodeProps { | ||
/** | ||
* The string with html entities to decode | ||
* | ||
* ```jsx | ||
* <HtmlDecoder value="Hello world! – foo bar –" /> | ||
* ``` | ||
*/ | ||
html: string; | ||
} | ||
|
||
/** | ||
* The `HtmlDecoder` simply decodes html entities | ||
* | ||
* Any actual html markup gets stripped before decoding html entities. If you need to render HTML use {@link SafeHtml} | ||
* | ||
* ## Usage | ||
* | ||
* ```jsx | ||
* <HtmlDecoder html="Hello world! – foo bar –" /> | ||
* ``` | ||
* | ||
* @param props Component properties | ||
* | ||
* @category React Components | ||
*/ | ||
export const HtmlDecoder: FC<HtmlDecodeProps> = ({ html }) => { | ||
return <>{parse(stripTags(html))}</>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { FC } from 'react'; | ||
import parse from 'html-react-parser'; | ||
import type { IWhiteList } from 'xss'; | ||
import { wpKsesPost } from '../../dom'; | ||
|
||
export interface SafeHtmlProps { | ||
/** | ||
* The HTML string to be rendered. | ||
* | ||
* ```jsx | ||
* <SafeHtml html="<div><p>hello world</p> div content</div>" /> | ||
* ``` | ||
*/ | ||
html: string; | ||
|
||
/** | ||
* The allow list for the parser | ||
* | ||
* ```jsx | ||
* <SafeHtml | ||
* html="<div><p>hello world</p> div content</div>" | ||
* ksesAllowList={{ div: [] }} | ||
* /> | ||
* ``` | ||
*/ | ||
ksesAllowList?: IWhiteList; | ||
} | ||
|
||
/** | ||
* The `SafeHtml` component provides an easy way to safely render HTML | ||
* | ||
* The html prop is sanitized through {@link wpKsesPost} so it's safe for rendering arbitrary html markup. | ||
* | ||
* ## Usage | ||
* | ||
* ```jsx | ||
* <SafeHtml html="<div><p>hello world</p> div content</div>" /> | ||
* ``` | ||
* | ||
* @param props Component properties | ||
* | ||
* @category React Components | ||
*/ | ||
export const SafeHtml: FC<SafeHtmlProps> = ({ html, ksesAllowList }) => { | ||
return <>{parse(wpKsesPost(html, ksesAllowList))}</>; | ||
}; |
24 changes: 24 additions & 0 deletions
24
packages/core/src/react/components/__tests__/HtmlDecoder.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import * as React from 'react'; | ||
import { render } from '@testing-library/react'; | ||
import { HtmlDecoder } from '../HtmlDecoder'; | ||
|
||
describe('HtmlDecoder', () => { | ||
it('decodes entities', () => { | ||
const { container } = render( | ||
<HtmlDecoder html="Hello world! – foo bar – ‘\@£#?,’\[]" />, | ||
); | ||
|
||
expect(container.firstChild).toMatchInlineSnapshot( | ||
`Hello world! – foo bar – ‘\\@£#?,’\\[]`, | ||
); | ||
}); | ||
|
||
it('does not render arbitrary markup', () => { | ||
const { container } = render(<HtmlDecoder html="This is a <span>title</span>" />); | ||
expect(container).toMatchInlineSnapshot(` | ||
<div> | ||
This is a title | ||
</div> | ||
`); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import * as React from 'react'; | ||
import { render } from '@testing-library/react'; | ||
import { SafeHtml } from '../SafeHtml'; | ||
|
||
describe('SafeHtml', () => { | ||
it('renders entities', () => { | ||
const { container } = render( | ||
<SafeHtml html="Hello world! – foo bar – ‘\@£#?,’\[]" />, | ||
); | ||
|
||
expect(container.firstChild).toMatchInlineSnapshot( | ||
`Hello world! – foo bar – ‘\\@£#?,’\\[]`, | ||
); | ||
}); | ||
|
||
it('renders arbitrary markup', () => { | ||
const { container } = render(<SafeHtml html="This is a <span>title</span>" />); | ||
expect(container).toMatchInlineSnapshot(` | ||
<div> | ||
This is a | ||
<span> | ||
title | ||
</span> | ||
</div> | ||
`); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
export * from './BlocksRenderer'; | ||
export * from './Menu'; | ||
export * from './SafeHtml'; | ||
export * from './HtmlDecoder'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
df3e65c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
headstarwp – ./
headstarwp-git-develop-tenup-internal.vercel.app
headstartwp.vercel.app
headstarwp-tenup-internal.vercel.app