fix: limit maximum quote depth to 3

This commit is contained in:
Paul Makles 2022-07-08 15:19:16 +01:00
parent 34bb2bbc13
commit 4a85dd69cf
3 changed files with 34 additions and 9 deletions

View file

@ -3,11 +3,13 @@ import { Suspense, lazy } from "preact/compat";
const Renderer = lazy(() => import("./RemarkRenderer")); const Renderer = lazy(() => import("./RemarkRenderer"));
export interface MarkdownProps { export interface MarkdownProps {
content?: string | null; content: string;
disallowBigEmoji?: boolean; disallowBigEmoji?: boolean;
} }
export default function Markdown(props: MarkdownProps) { export default function Markdown(props: MarkdownProps) {
if (!props.content) return null;
return ( return (
// @ts-expect-error Typings mis-match. // @ts-expect-error Typings mis-match.
<Suspense fallback={props.content}> <Suspense fallback={props.content}>

View file

@ -15,14 +15,14 @@ import { memo } from "preact/compat";
import { useEffect, useMemo, useState } from "preact/hooks"; import { useEffect, useMemo, useState } from "preact/hooks";
import { MarkdownProps } from "./Markdown"; import { MarkdownProps } from "./Markdown";
import { handlers } from "./hast";
import { RenderCodeblock } from "./plugins/Codeblock"; import { RenderCodeblock } from "./plugins/Codeblock";
import { RenderAnchor } from "./plugins/anchors"; import { RenderAnchor } from "./plugins/anchors";
import { remarkChannels, RenderChannel } from "./plugins/channels"; import { remarkChannels, RenderChannel } from "./plugins/channels";
import { isOnlyEmoji, remarkEmoji, RenderEmoji } from "./plugins/emoji"; import { isOnlyEmoji, remarkEmoji, RenderEmoji } from "./plugins/emoji";
import { remarkMention, RenderMention } from "./plugins/mentions"; import { remarkMention, RenderMention } from "./plugins/mentions";
import { passThroughComponents } from "./plugins/remarkRegexComponent";
import { remarkSpoiler, RenderSpoiler } from "./plugins/spoiler"; import { remarkSpoiler, RenderSpoiler } from "./plugins/spoiler";
import { remarkTimestamps, timestampHandler } from "./plugins/timestamps"; import { remarkTimestamps } from "./plugins/timestamps";
import "./prism"; import "./prism";
/** /**
@ -139,10 +139,7 @@ const render = unified()
.use(remarkEmoji) .use(remarkEmoji)
.use(remarkMention) .use(remarkMention)
.use(remarkRehype, { .use(remarkRehype, {
handlers: { handlers,
...passThroughComponents("emoji", "spoiler", "mention", "channel"),
timestamp: timestampHandler,
},
}) })
.use(rehypeKatex, { .use(rehypeKatex, {
maxSize: 10, maxSize: 10,
@ -173,15 +170,34 @@ const Container = styled.div<{ largeEmoji: boolean }>`
--emoji-size: ${(props) => (props.largeEmoji ? "3em" : "1.25em")}; --emoji-size: ${(props) => (props.largeEmoji ? "3em" : "1.25em")};
`; `;
/**
* Regex for matching execessive blockquotes
*/
const RE_QUOTE = /(^[>\s][>\s])[>\s]+([^]+)$/gm;
/**
* Sanitise Markdown input before rendering
* @param content Input string
* @returns Sanitised string
*/
function sanitise(content: string) {
// Strip excessive blockquote indentation
return content.replace(RE_QUOTE, (_, m0, m1) => m0 + m1);
}
/** /**
* Remark renderer component * Remark renderer component
*/ */
export default memo(({ content, disallowBigEmoji }: MarkdownProps) => { export default memo(({ content, disallowBigEmoji }: MarkdownProps) => {
const sanitisedContent = useMemo(() => sanitise(content), [content]);
const [Content, setContent] = useState<React.ReactElement>(null!); const [Content, setContent] = useState<React.ReactElement>(null!);
useEffect(() => { useEffect(() => {
render.process(content!).then((file) => setContent(file.result)); render
}, [content]); .process(sanitisedContent)
.then((file) => setContent(file.result));
}, [sanitisedContent]);
const largeEmoji = useMemo( const largeEmoji = useMemo(
() => !disallowBigEmoji && isOnlyEmoji(content!), () => !disallowBigEmoji && isOnlyEmoji(content!),

View file

@ -0,0 +1,7 @@
import { passThroughComponents } from "./plugins/remarkRegexComponent";
import { timestampHandler } from "./plugins/timestamps";
export const handlers = {
...passThroughComponents("emoji", "spoiler", "mention", "channel"),
timestamp: timestampHandler,
};