Skip to content

Commit 3de6f93

Browse files
chore(deps): Replace showdown dependency with marked (#370)
* chore(deps): Replace showdown dependency with marked * Downgrade marked to support older node versions * Fix lint errors * Update to marked 4 to prevent security issues
1 parent cc8558f commit 3de6f93

File tree

8 files changed

+66
-67
lines changed

8 files changed

+66
-67
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,6 @@
112112
"!**/node_modules/**"
113113
],
114114
"resolver": "./jest-resolver.js"
115-
}
115+
},
116+
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
116117
}

packages/dev/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"react-dom": "^16.14.0",
2323
"react-i18next": "^11.7.3",
2424
"react-router-dom": "^5.2.0",
25-
"showdown": "2.1.0",
25+
"marked": "^4.0.0",
2626
"lodash-es": "^4.17.21"
2727
},
2828
"devDependencies": {

packages/module/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"@patternfly/react-core": ">=4.115.2",
4949
"react": ">=16.8.0",
5050
"react-dom": ">=16.8.0",
51-
"showdown": ">=2.1.0"
51+
"marked": "^4.0.0"
5252
},
5353
"dependencies": {
5454
"@patternfly/react-catalog-view-extension": "^4.93.15",

packages/module/src/ConsoleInternal/components/markdown-view.tsx

Lines changed: 34 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { css } from '@patternfly/react-styles';
3-
import { Converter } from 'showdown';
3+
import { marked } from 'marked';
44
import { useForceRender } from '@console/shared';
55
import { QuickStartContext, QuickStartContextValues } from '../../utils/quick-start-context';
66
import './_markdown-view.scss';
@@ -16,18 +16,7 @@ type ShowdownExtension = {
1616
replace?: (...args: any[]) => string;
1717
};
1818

19-
export const markdownConvert = (markdown, extensions?: ShowdownExtension[]) => {
20-
const converter = new Converter({
21-
tables: true,
22-
openLinksInNewWindow: true,
23-
strikethrough: true,
24-
emoji: false,
25-
});
26-
27-
if (extensions) {
28-
converter.addExtension(extensions);
29-
}
30-
19+
export const markdownConvert = async (markdown: string, extensions?: ShowdownExtension[]) => {
3120
DOMPurify.addHook('beforeSanitizeElements', function(node) {
3221
// nodeType 1 = element type
3322

@@ -62,40 +51,26 @@ export const markdownConvert = (markdown, extensions?: ShowdownExtension[]) => {
6251
}
6352
});
6453

65-
return DOMPurify.sanitize(converter.makeHtml(markdown), {
66-
USE_PROFILES: {
67-
html: true,
68-
svg: true,
69-
},
70-
// ALLOWED_TAGS: [
71-
// 'b',
72-
// 'i',
73-
// 'strike',
74-
// 's',
75-
// 'del',
76-
// 'em',
77-
// 'strong',
78-
// 'a',
79-
// 'p',
80-
// 'h1',
81-
// 'h2',
82-
// 'h3',
83-
// 'h4',
84-
// 'ul',
85-
// 'ol',
86-
// 'li',
87-
// 'code',
88-
// 'pre',
89-
// 'button',
90-
// ...tableTags,
91-
// 'div',
92-
// 'img',
93-
// 'span',
94-
// 'svg',
95-
// ],
96-
// ALLOWED_ATTR: ['href', 'target', 'rel', 'class', 'src', 'alt', 'id'],
97-
// ALLOWED_URI_REGEXP: /^(?:(?:https?|mailto|didact):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i,
98-
});
54+
// Replace code fences with non markdown formatting relates tokens so that marked doesn't try to parse them as code spans
55+
const markdownWithSubstitutedCodeFences = markdown.replace(/```/g, '@@@');
56+
const parsedMarkdown = await marked.parse(markdownWithSubstitutedCodeFences);
57+
// Swap the temporary tokens back to code fences before we run the extensions
58+
let md = parsedMarkdown.replace(/@@@/g, '```');
59+
60+
if (extensions) {
61+
// Convert code spans back to md format before we run the custom extension regexes
62+
md = md.replace(/<code>(.*)<\/code>/g, '`$1`');
63+
64+
extensions.forEach(({ regex, replace }) => {
65+
if (regex) {
66+
md = md.replace(regex, replace);
67+
}
68+
});
69+
70+
// Convert any remaining backticks back into code spans
71+
md = md.replace(/`(.*)`/g, '<code>$1</code>');
72+
}
73+
return DOMPurify.sanitize(md);
9974
};
10075

10176
type SyncMarkdownProps = {
@@ -126,9 +101,18 @@ export const SyncMarkdownView: React.FC<SyncMarkdownProps> = ({
126101
className,
127102
}) => {
128103
const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
129-
const markup = React.useMemo(() => {
130-
return markdownConvert(content || emptyMsg || getResource('Not available'), extensions);
131-
}, [content, emptyMsg, extensions, getResource]);
104+
const [markup, setMarkup] = React.useState<string>('');
105+
106+
React.useEffect(() => {
107+
async function getMd() {
108+
const md = await markdownConvert(
109+
content || emptyMsg || getResource('Not available'),
110+
extensions,
111+
);
112+
setMarkup(md);
113+
}
114+
getMd();
115+
}, [content, emptyMsg, getResource, extensions]);
132116
const innerProps: InnerSyncMarkdownProps = {
133117
renderExtension: extensions?.length > 0 ? renderExtension : undefined,
134118
exactHeight,

packages/module/src/QuickStartPanelContent.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const QuickStartPanelContent: React.FC<QuickStartPanelContentProps> = ({
6060
QuickStartContext,
6161
);
6262
const [contentRef, setContentRef] = React.useState<HTMLDivElement>();
63+
const [displayName, setDisplayName] = React.useState<string>('');
6364
const shadows = useScrollShadows(contentRef);
6465
const quickStart = quickStarts.find((qs) => qs.metadata.name === activeQuickStartID);
6566
const taskNumber = activeQuickStartState?.taskNumber;
@@ -96,6 +97,14 @@ const QuickStartPanelContent: React.FC<QuickStartPanelContentProps> = ({
9697
}
9798
}, [quickStart]);
9899

100+
React.useEffect(() => {
101+
async function getDisplayName() {
102+
const convertedMdDisplayName = await markdownConvert(quickStart?.spec.displayName);
103+
setDisplayName(removeParagraphWrap(convertedMdDisplayName));
104+
}
105+
getDisplayName();
106+
}, [quickStart]);
107+
99108
const content = quickStart ? (
100109
<DrawerPanelContent
101110
isResizable={isResizable}
@@ -116,7 +125,7 @@ const QuickStartPanelContent: React.FC<QuickStartPanelContentProps> = ({
116125
>
117126
<span
118127
dangerouslySetInnerHTML={{
119-
__html: removeParagraphWrap(markdownConvert(quickStart?.spec.displayName)),
128+
__html: displayName,
120129
}}
121130
/>{' '}
122131
<small className="pfext-quick-start-panel-content__duration">

packages/module/src/controller/QuickStartTaskHeader.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,23 @@ const QuickStartTaskHeader: React.FC<QuickStartTaskHeaderProps> = ({
6464
children,
6565
}) => {
6666
const titleRef = React.useRef(null);
67+
const [parsedTitle, setParsedTitle] = React.useState<string>('');
68+
6769
React.useEffect(() => {
6870
if (isActiveTask) {
6971
// Focus the WizardNavItem button element that contains the title
7072
titleRef.current.parentNode.focus();
7173
}
7274
}, [isActiveTask]);
75+
76+
React.useEffect(() => {
77+
async function getParsedTitle() {
78+
const convertedMdTitle = await markdownConvert(title);
79+
setParsedTitle(removeParagraphWrap(convertedMdTitle));
80+
}
81+
getParsedTitle();
82+
}, [title]);
83+
7384
const classNames = css('pfext-quick-start-task-header__title', {
7485
'pfext-quick-start-task-header__title-success': taskStatus === QuickStartTaskStatus.SUCCESS,
7586
'pfext-quick-start-task-header__title-failed':
@@ -92,7 +103,7 @@ const QuickStartTaskHeader: React.FC<QuickStartTaskHeaderProps> = ({
92103
<div className="pfext-quick-start-task-header" ref={titleRef}>
93104
<TaskIcon taskIndex={taskIndex} taskStatus={taskStatus} />
94105
<Title headingLevel="h3" size={size} className={classNames}>
95-
<span dangerouslySetInnerHTML={{ __html: removeParagraphWrap(markdownConvert(title)) }} />
106+
<span dangerouslySetInnerHTML={{ __html: parsedTitle }} />
96107
{isActiveTask && subtitle && (
97108
<span
98109
className="pfext-quick-start-task-header__subtitle"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
declare module '*.scss';
22
declare module '*.json';
3+
declare module 'marked';

yarn.lock

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4630,11 +4630,6 @@ commander@^7.0.0, commander@~7.2.0:
46304630
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
46314631
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
46324632

4633-
commander@^9.0.0:
4634-
version "9.5.0"
4635-
resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30"
4636-
integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==
4637-
46384633
common-log-format@~0.1.3:
46394634
version "0.1.4"
46404635
resolved "https://registry.yarnpkg.com/common-log-format/-/common-log-format-0.1.4.tgz#39ba6ccb5c46c2f89aa92f232866d18f18075ba9"
@@ -10650,6 +10645,11 @@ markdown-table@^2.0.0:
1065010645
dependencies:
1065110646
repeat-string "^1.0.0"
1065210647

10648+
marked@^4.0.0:
10649+
version "4.3.0"
10650+
resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3"
10651+
integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==
10652+
1065310653
matcher-collection@^2.0.0:
1065410654
version "2.0.1"
1065510655
resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-2.0.1.tgz#90be1a4cf58d6f2949864f65bb3b0f3e41303b29"
@@ -14263,13 +14263,6 @@ shortid@^2.2.8:
1426314263
dependencies:
1426414264
nanoid "^2.1.0"
1426514265

14266-
14267-
version "2.1.0"
14268-
resolved "https://registry.yarnpkg.com/showdown/-/showdown-2.1.0.tgz#1251f5ed8f773f0c0c7bfc8e6fd23581f9e545c5"
14269-
integrity sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==
14270-
dependencies:
14271-
commander "^9.0.0"
14272-
1427314266
side-channel@^1.0.4:
1427414267
version "1.0.4"
1427514268
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"

0 commit comments

Comments
 (0)