Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
setting html DANGEROUSLY
  • Loading branch information
jennspencer committed May 9, 2024
commit 3ca6ecc9eb8300d519b357fe0e6876233229c1e5
69 changes: 0 additions & 69 deletions components/HTMLBlock/index.jsx

This file was deleted.

36 changes: 36 additions & 0 deletions components/HTMLBlock/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { useEffect } from 'react';
import { renderToString, renderToStaticMarkup } from 'react-dom/server';

const MATCH_SCRIPT_TAGS = /<script\b[^>]*>([\s\S]*?)<\/script *>\n?/gim;

const extractScripts = (html: string = ''): [string, () => void] => {
const scripts: string[] = [];
let match: RegExpExecArray | null;
while ((match = MATCH_SCRIPT_TAGS.exec(html)) !== null) {
scripts.push(match[1]);
}
const cleaned = html.replace(MATCH_SCRIPT_TAGS, '');
return [cleaned, () => scripts.map(js => window.eval(js))];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like, there's no reason to strip script tags if the whole thing is getting executed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it only gets executed if you pass runScripts=true? we should probably leave it to the user to decide whether or not they wanna get h4x0rd

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTML blocks were originally a way to say, hey this code is dangerous and we know it. All other 'inlined' html would get tags and attributes sanitized. But I don't see how we could even begin to sanitize MDX.

The only thing I can think of, is if some existing page with an html block has an unknown malicious script in it, and all of sudden we gave it life?

};

const HTMLBlock = props => {
const { children, runScripts, safeMode = false } = props;
const html = renderToString(<>{children}</>);
const [cleanedHtml, exec] = extractScripts(html);

useEffect(() => {
if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts) exec();
}, [runScripts, exec]);

if (safeMode) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

safeMode was my silly attempt to make suggested edits safer. Suggested edits could be submitted by anonymous users. And it features a preview mode, so if the submitter wasn't an admin, we wouldn't render the HTML. 🤷🏼

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that was the usage for us sure, but i'm wondering about the 1000 or downloads a week of @readme/markdown? is this new improved renderer going to be internal only or are we improving on the current one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, we can figure out the final details in another PR since it's a bit out of scope for this one 😅

return (
<pre className="html-unsafe">
<code dangerouslySetInnerHTML={{ __html: renderToStaticMarkup(cleanedHtml) }} />
</pre>
);
}

return <div className="rdmd-html" dangerouslySetInnerHTML={{ __html: html }} />;
};

export default HTMLBlock;
18 changes: 2 additions & 16 deletions components/Image/index.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,18 @@
import * as React from 'react';

interface Props extends React.PropsWithChildren<React.HTMLAttributes<HTMLImageElement>> {
align: string;
alt: string;
border: boolean;
caption: string;
className: string;
height: string;
lazy: boolean;
src: string;
title: string;
width: string;
}

const Image = (props: Props) => {
const Image = props => {
const [lightbox, setLightbox] = React.useState(false);

const {
align = '',
alt = '',
border = false,
caption,
className = '',
height = 'auto',
lazy,
src = '',
title = '',
width = 'auto',
lazyImages: lazy = true,
} = props;

if (className === 'emoji') {
Expand Down
23 changes: 4 additions & 19 deletions docs/sanitizing-tests.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,7 @@

## Sanitizing `style` tags

<style>
* {
background-color: olive;
}
</style>


## Sanitizing `style` attributes

<p style="background-color: salmon">fish content</p>


## Sanitizing html blocks

[block:html]
{
"html": "<style>* { border: 3px solid magenta; }</style>"
}
[/block]
<HTMLBlock>
<h2>Header</h2>
<p>hello there</p>
</HTMLBlock>
1 change: 1 addition & 0 deletions enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export enum NodeTypes {
emoji = 'emoji',
i = 'i',
image = 'image',
htmlBlock = 'html-block',
}
1 change: 1 addition & 0 deletions index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const makeUseMDXComponents = (more: RunOpts['components']) => {
...Components,
Variable,
'code-tabs': Components.CodeTabs,
'html-block': Components.HTMLBlock,
img: Components.Image,
};

Expand Down
9 changes: 0 additions & 9 deletions processor/compile/html-block.js

This file was deleted.

8 changes: 8 additions & 0 deletions processor/compile/html-block.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { HTMLBlock } from '../../types';

const htmlBlock = (node: HTMLBlock) => {
const html = node.data.hProperties.html;
return `<HTMLBlock>${JSON.stringify({ html }, null, 2)}</HTMLBlock>`;
}

export default htmlBlock;
2 changes: 2 additions & 0 deletions processor/compile/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import gemoji from './gemoji';
import codeTabs from './code-tabs';
import image from './image';
import htmlBlock from './html-block';
import { NodeTypes } from '../../enums';

const compilers = {
handlers: {
[NodeTypes.emoji]: gemoji,
[NodeTypes.codeTabs]: codeTabs,
[NodeTypes.image]: image,
[NodeTypes.htmlBlock]: htmlBlock,
},
};

Expand Down
10 changes: 10 additions & 0 deletions types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ interface CodeTabs extends Parent {
};
}

interface HTMLBlock extends Parent {
type: NodeTypes.htmlBlock;
data: Data & {
hName: 'html-block';
hProperties: {
html: string;
};
};
}

interface Gemoji extends Literal {
type: NodeTypes.emoji;
name: string;
Expand Down