Skip to content

Commit

Permalink
Fix to sanitize by default
Browse files Browse the repository at this point in the history
The docs have always said `remark-html` is safe by default.
It wasn’t and this patches that.

If you do want to be unsafe, use `remark-html` with `sanitize: false`:

```diff
  -.use(remarkHtml)
  +.use(remarkHtml, {sanitize: false})
```
  • Loading branch information
wooorm committed Sep 7, 2021
1 parent 3507d99 commit b75c9dd
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 34 deletions.
28 changes: 19 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,36 @@ import {toHast} from 'mdast-util-to-hast'
*
* @type {import('unified').Plugin<[Options?]|void[], Root, string>}
*/
export default function remarkHtml(options = {}) {
const handlers = options.handlers || {}
const schema =
options.sanitize && typeof options.sanitize === 'object'
? options.sanitize
: undefined
export default function remarkHtml(settings) {
const options = {...(settings || {})}
/** @type {boolean|undefined} */
let clean

if (typeof options.sanitize === 'boolean') {
clean = options.sanitize
options.sanitize = undefined
}

if (typeof clean !== 'boolean') {
clean = true
}

Object.assign(this, {Compiler: compiler})

/**
* @type {import('unified').CompilerFunction<Root, string>}
*/
function compiler(node, file) {
const hast = toHast(node, {allowDangerousHtml: !options.sanitize, handlers})
const hast = toHast(node, {
allowDangerousHtml: !clean,
handlers: options.handlers
})
// @ts-expect-error: assume root.
const cleanHast = options.sanitize ? sanitize(hast, schema) : hast
const cleanHast = clean ? sanitize(hast, options.sanitize) : hast
const result = toHtml(
// @ts-expect-error: assume root.
cleanHast,
Object.assign({}, options, {allowDangerousHtml: !options.sanitize})
Object.assign({}, options, {allowDangerousHtml: !clean})
)

if (file.extname) {
Expand Down
53 changes: 28 additions & 25 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@ test('remarkHtml', (t) => {
'should throw when not given a node'
)

let processor = remark().use(remarkHtml)
let processorDangerous = remark().use(remarkHtml, {sanitize: false})

t.equal(
// @ts-expect-error: unknown node.
processor.stringify({type: 'alpha'}),
processorDangerous.stringify({type: 'alpha'}),
'<div></div>',
'should stringify unknown nodes'
)

t.equal(
processor.stringify({
processorDangerous.stringify({
// @ts-expect-error: unknown node.
type: 'alpha',
children: [{type: 'strong', children: [{type: 'text', value: 'bravo'}]}]
Expand All @@ -61,7 +61,7 @@ test('remarkHtml', (t) => {
)

t.equal(
processor.stringify({
processorDangerous.stringify({
// @ts-expect-error: unknown node.
type: 'alpha',
children: [{type: 'text', value: 'bravo'}],
Expand All @@ -75,7 +75,8 @@ test('remarkHtml', (t) => {
'should stringify unknown nodes'
)

processor = remark().use(remarkHtml, {
processorDangerous = remark().use(remarkHtml, {
sanitize: false,
handlers: {
/** @param {Paragraph} node */
paragraph(h, node) {
Expand All @@ -91,12 +92,12 @@ test('remarkHtml', (t) => {
})

t.equal(
processor.processSync('paragraph text').toString(),
processorDangerous.processSync('paragraph text').toString(),
'<p>changed</p>\n',
'should allow overriding handlers'
)

processor = remark()
processorDangerous = remark()
.use(
/** @type {import('unified').Plugin<void[], Root>} */
() => (ast) => {
Expand All @@ -106,31 +107,33 @@ test('remarkHtml', (t) => {
}
}
)
.use(remarkHtml)
.use(remarkHtml, {sanitize: false})

t.equal(
processor.processSync('![hello](example.jpg "overwritten")').toString(),
processorDangerous
.processSync('![hello](example.jpg "overwritten")')
.toString(),
'<p><img src="example.jpg" alt="hello" title="overwrite"></p>\n',
'should patch and merge attributes'
)

processor = remark()
processorDangerous = remark()
.use(
/** @type {import('unified').Plugin<void[], Root>} */
() => (ast) => {
// @ts-expect-error: assume it exists.
ast.children[0].children[0].data = {hName: 'b'}
}
)
.use(remarkHtml)
.use(remarkHtml, {sanitize: false})

t.equal(
processor.processSync('**Bold!**').toString(),
processorDangerous.processSync('**Bold!**').toString(),
'<p><b>Bold!</b></p>\n',
'should overwrite a tag-name'
)

processor = remark()
processorDangerous = remark()
.use(
/** @type {import('unified').Plugin<void[], Root>} */
() => (ast) => {
Expand All @@ -149,15 +152,15 @@ test('remarkHtml', (t) => {
}
}
)
.use(remarkHtml)
.use(remarkHtml, {sanitize: false})

t.equal(
processor.processSync('`var`').toString(),
processorDangerous.processSync('`var`').toString(),
'<p><code><span class="token">var</span></code></p>\n',
'should overwrite content'
)

processor = remark()
processorDangerous = remark()
.use(
/** @type {import('unified').Plugin<void[], Root>} */
() => (ast) => {
Expand All @@ -179,12 +182,12 @@ test('remarkHtml', (t) => {
.use(remarkHtml, {sanitize: true})

t.equal(
processor.processSync('`var`').toString(),
processorDangerous.processSync('`var`').toString(),
'<p><code>var</code></p>\n',
'should not overwrite content in `sanitize` mode'
)

processor = remark()
processorDangerous = remark()
.use(
/** @type {import('unified').Plugin<void[], Root>} */
() => (ast) => {
Expand All @@ -193,10 +196,10 @@ test('remarkHtml', (t) => {
}
}
)
.use(remarkHtml)
.use(remarkHtml, {sanitize: false})

t.equal(
processor.processSync('```js\nvar\n```\n').toString(),
processorDangerous.processSync('```js\nvar\n```\n').toString(),
'<pre><code class="foo">var\n</code></pre>\n',
'should overwrite classes on code'
)
Expand All @@ -206,8 +209,8 @@ test('remarkHtml', (t) => {
.use(remarkHtml)
.processSync('## Hello <span>world</span>')
.toString(),
'<h2>Hello <span>world</span></h2>\n',
'should be `sanitation: false` by default'
'<h2>Hello world</h2>\n',
'should be `sanitation: true` by default'
)

t.equal(
Expand All @@ -224,7 +227,7 @@ test('remarkHtml', (t) => {
.use(remarkHtml, {sanitize: null})
.processSync('## Hello <span>world</span>')
.toString(),
'<h2>Hello <span>world</span></h2>\n',
'<h2>Hello world</h2>\n',
'should support sanitation: null'
)

Expand Down Expand Up @@ -294,7 +297,7 @@ test('CommonMark', (t) => {

const actual = unified()
.use(remarkParse)
.use(remarkHtml)
.use(remarkHtml, {sanitize: false})
.processSync(example.markdown)
.toString()

Expand Down Expand Up @@ -337,7 +340,7 @@ test('Integrations', (t) => {
const result = remark()
// @ts-expect-error: fine.
.use(integrationMap[name])
.use(remarkHtml)
.use(remarkHtml, {sanitize: false})
.processSync(file)
.toString()

Expand Down

0 comments on commit b75c9dd

Please sign in to comment.