From f59c5143630e948c91e88fa3e9b621a2b1d346b5 Mon Sep 17 00:00:00 2001
From: Hentry Martin
Date: Tue, 14 Jan 2025 22:07:19 +0100
Subject: [PATCH 01/11] fix: privacy violations
---
src/shared/containers/Profile.jsx | 15 ++++++-
src/shared/containers/ProfileStats.jsx | 11 ++++-
src/shared/containers/Toastr/index.jsx | 8 +++-
src/shared/utils/markdown.js | 56 +++++++++++++++++++++++---
4 files changed, 81 insertions(+), 9 deletions(-)
diff --git a/src/shared/containers/Profile.jsx b/src/shared/containers/Profile.jsx
index af011788f8..be4497a268 100644
--- a/src/shared/containers/Profile.jsx
+++ b/src/shared/containers/Profile.jsx
@@ -144,7 +144,20 @@ class ProfileContainer extends React.Component {
{
info ? (
) :
}
diff --git a/src/shared/containers/ProfileStats.jsx b/src/shared/containers/ProfileStats.jsx
index 56ae4ce25e..03c87fb7da 100644
--- a/src/shared/containers/ProfileStats.jsx
+++ b/src/shared/containers/ProfileStats.jsx
@@ -99,7 +99,16 @@ class ProfileStatsContainer extends React.Component {
isLoading ?
: (
)
}
diff --git a/src/shared/containers/Toastr/index.jsx b/src/shared/containers/Toastr/index.jsx
index ba313e9de8..4c68fcf82b 100644
--- a/src/shared/containers/Toastr/index.jsx
+++ b/src/shared/containers/Toastr/index.jsx
@@ -78,7 +78,13 @@ class ExtendedReduxToastr extends ReduxToastr {
inMemory={this.toastrFired}
addToMemory={() => this._addToMemory(item.id)}
item={mergedItem}
- {...this.props}
+ toastrs={this.props.toastrs}
+ preventDuplicates={this.props.preventDuplicates}
+ position={this.props.position}
+ transitionIn={this.props.transitionIn}
+ transitionOut={this.props.transitionOut}
+ progressBar={this.props.progressBar}
+ showCloseButton={this.props.showCloseButton}
/>
{item.options && item.options.attention
&& (
diff --git a/src/shared/utils/markdown.js b/src/shared/utils/markdown.js
index 5e0883bf04..db74cb9f7f 100644
--- a/src/shared/utils/markdown.js
+++ b/src/shared/utils/markdown.js
@@ -13,6 +13,7 @@ import { Button, PrimaryButton, SecondaryButton } from 'topcoder-react-ui-kit';
import { Link } from 'topcoder-react-utils';
import hljs from 'highlight.js';
import ReactHtmlParser from 'react-html-parser';
+import xss from 'xss';
import sub from 'markdown-it-sub';
import sup from 'markdown-it-sup';
import 'highlight.js/styles/github.css';
@@ -77,6 +78,31 @@ const buttonThemes = {
bs,
};
+const safeHtmlTags = [
+ // Content Sectioning
+ "address", "article", "aside", "footer", "header", "h1", "h2", "h3", "h4", "h5", "h6", "main", "nav", "section",
+
+ // Text Content
+ "blockquote", "dd", "div", "dl", "dt", "figcaption", "figure", "hr", "li", "ol", "p", "pre", "ul",
+
+ // Inline Text Semantics
+ "a", "abbr", "b", "bdi", "bdo", "br", "cite", "code", "data", "dfn", "em", "i", "kbd", "mark", "q", "rp", "rt",
+ "ruby", "s", "samp", "small", "span", "strong", "sub", "sup", "time", "u", "var", "wbr",
+
+ // Image and Multimedia
+ "img", "audio", "video", "source", "track", "picture",
+
+ // Table Content
+ "caption", "col", "colgroup", "table", "tbody", "td", "tfoot", "th", "thead", "tr",
+
+ // Forms and Interactive Elements
+ "button", "fieldset", "form", "input", "label", "legend", "meter", "optgroup", "option", "output", "progress",
+ "select", "textarea",
+
+ // Scripting and No-Scripting
+ "noscript"
+];
+
/**
* Add new Custom Components here.
*
@@ -165,6 +191,24 @@ function getProps(token, key) {
return normalizeProps(res);
}
+/**
+ * Check if the tag is safe to render.
+ * @param {String} tag
+ * @returns
+ */
+function checkForSafeTag(tag) {
+ return safeHtmlTags.includes(tag);
+}
+
+/**
+ * Sanitize content
+ * @param {String} content
+ * @returns
+ */
+function sanitizeContent(content) {
+ return xss(content);
+}
+
/**
* Renders tokens with zero nesting.
* @param {Object} tokens
@@ -184,7 +228,7 @@ function renderToken(tokens, index, md) {
return renderTokens(token.children, 0, md);
/* eslint-enable no-use-before-define */
case 'text':
- return token.content;
+ return sanitizeContent(token.content);
case 'fence':
return Highlighter({
codeString: token.content,
@@ -204,9 +248,9 @@ function renderToken(tokens, index, md) {
}
default:
return React.createElement(
- token.tag,
+ checkForSafeTag(token.tag) ? token.tag : 'div',
getProps(token, index),
- token.content || undefined,
+ sanitizeContent(token.content) || undefined,
);
}
}
@@ -232,7 +276,7 @@ function renderTokens(tokens, startFrom, md) {
} else if (level === 0) {
if (token.nesting === 1) {
output.push(React.createElement(
- token.tag,
+ checkForSafeTag(token.tag) ? token.tag : "div",
getProps(token, pos),
renderTokens(tokens, 1 + pos, md),
));
@@ -252,11 +296,11 @@ function renderTokens(tokens, startFrom, md) {
}
props = normalizeProps(props);
if (selfClosing) {
- output.push(React.createElement(tag, { key: pos, ...props }));
+ output.push(React.createElement(checkForSafeTag(tag) ? tag : "div", { key: pos, ...props }));
} else {
level += 1;
output.push(React.createElement(
- tag,
+ checkForSafeTag(tag) ? tag : "div",
{ key: pos, ...props },
renderTokens(tokens, pos + 1, md),
));
From 39565d7522a2a3922056ac46b8888dd1c2339395 Mon Sep 17 00:00:00 2001
From: Hentry Martin
Date: Tue, 14 Jan 2025 22:46:20 +0100
Subject: [PATCH 02/11] fix: lint
---
src/shared/containers/Profile.jsx | 32 +++++++++++++++-----------
src/shared/containers/ProfileStats.jsx | 27 ++++++++++++++--------
src/shared/utils/markdown.js | 18 +++++++--------
3 files changed, 44 insertions(+), 33 deletions(-)
diff --git a/src/shared/containers/Profile.jsx b/src/shared/containers/Profile.jsx
index be4497a268..2a8df70e4f 100644
--- a/src/shared/containers/Profile.jsx
+++ b/src/shared/containers/Profile.jsx
@@ -135,6 +135,7 @@ class ProfileContainer extends React.Component {
const title = `${handleParam} | Community Profile | Topcoder`;
const description = `Meet Topcoder member ${handleParam} and view their skills and development and design activity. You can also see wins and tenure with Topcoder.`;
+ const {copilot, externalAccounts, externalLinks, challenges, skills, stats, lookupData, badges, meta, tcAcademyCertifications, tcAcademyCourses} = this.props;
return (
) :
}
@@ -183,6 +183,8 @@ ProfileContainer.defaultProps = {
ProfileContainer.propTypes = {
achievements: PT.arrayOf(PT.shape()),
+ badges: PT.shape(),
+ challenges: PT.arrayOf(PT.shape()),
copilot: PT.bool,
country: PT.string,
externalAccounts: PT.shape(),
@@ -201,6 +203,8 @@ ProfileContainer.propTypes = {
lookupData: PT.shape().isRequired,
meta: PT.shape(),
auth: PT.shape(),
+ tcAcademyCertifications: PT.arrayOf(PT.shape()),
+ tcAcademyCourses: PT.arrayOf(PT.shape()),
};
const mapStateToProps = (state, ownProps) => ({
diff --git a/src/shared/containers/ProfileStats.jsx b/src/shared/containers/ProfileStats.jsx
index 03c87fb7da..527e149224 100644
--- a/src/shared/containers/ProfileStats.jsx
+++ b/src/shared/containers/ProfileStats.jsx
@@ -81,6 +81,13 @@ class ProfileStatsContainer extends React.Component {
handleParam,
track,
subTrack,
+ stats,
+ tab,
+ setTab,
+ info,
+ statsDistribution,
+ statsHistory,
+ isAlreadyLoadChallenge,
} = this.props;
if (loadingError || !isValidTrack(track, subTrack)) {
@@ -99,16 +106,16 @@ class ProfileStatsContainer extends React.Component {
isLoading ?
: (
)
}
diff --git a/src/shared/utils/markdown.js b/src/shared/utils/markdown.js
index db74cb9f7f..0144420f58 100644
--- a/src/shared/utils/markdown.js
+++ b/src/shared/utils/markdown.js
@@ -80,27 +80,27 @@ const buttonThemes = {
const safeHtmlTags = [
// Content Sectioning
- "address", "article", "aside", "footer", "header", "h1", "h2", "h3", "h4", "h5", "h6", "main", "nav", "section",
+ 'address', 'article', 'aside', 'footer', 'header', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'main', 'nav', 'section',
// Text Content
- "blockquote", "dd", "div", "dl", "dt", "figcaption", "figure", "hr", "li", "ol", "p", "pre", "ul",
+ 'blockquote', 'dd', 'div', 'dl', 'dt', 'figcaption', 'figure', 'hr', 'li', 'ol', 'p', 'pre', 'ul',
// Inline Text Semantics
- "a", "abbr", "b", "bdi", "bdo", "br", "cite", "code", "data", "dfn", "em", "i", "kbd", "mark", "q", "rp", "rt",
- "ruby", "s", "samp", "small", "span", "strong", "sub", "sup", "time", "u", "var", "wbr",
+ 'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'code', 'data', 'dfn', 'em', 'i', 'kbd', 'mark', 'q', 'rp', 'rt',
+ 'ruby', 's', 'samp', 'small', 'span', 'strong', 'sub', 'sup', 'time', 'u', 'var', 'wbr',
// Image and Multimedia
- "img", "audio", "video", "source", "track", "picture",
+ 'img', 'audio', 'video', 'source', 'track', 'picture',
// Table Content
- "caption", "col", "colgroup", "table", "tbody", "td", "tfoot", "th", "thead", "tr",
+ 'caption', 'col', 'colgroup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr',
// Forms and Interactive Elements
- "button", "fieldset", "form", "input", "label", "legend", "meter", "optgroup", "option", "output", "progress",
- "select", "textarea",
+ 'button', 'fieldset', 'form', 'input', 'label', 'legend', 'meter', 'optgroup', 'option', 'output', 'progress',
+ 'select', 'textarea',
// Scripting and No-Scripting
- "noscript"
+ 'noscript'
];
/**
From 33f4564ca696b5b3762b717abd84f66605470ef6 Mon Sep 17 00:00:00 2001
From: Hentry Martin
Date: Tue, 14 Jan 2025 23:01:27 +0100
Subject: [PATCH 03/11] fix: lint
---
src/shared/containers/Profile.jsx | 25 ++++++++++++++++++-------
src/shared/utils/markdown.js | 18 +++++++++---------
2 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/src/shared/containers/Profile.jsx b/src/shared/containers/Profile.jsx
index 2a8df70e4f..d3f91eb194 100644
--- a/src/shared/containers/Profile.jsx
+++ b/src/shared/containers/Profile.jsx
@@ -135,7 +135,20 @@ class ProfileContainer extends React.Component {
const title = `${handleParam} | Community Profile | Topcoder`;
const description = `Meet Topcoder member ${handleParam} and view their skills and development and design activity. You can also see wins and tenure with Topcoder.`;
- const {copilot, externalAccounts, externalLinks, challenges, skills, stats, lookupData, badges, meta, tcAcademyCertifications, tcAcademyCourses} = this.props;
+ const {
+ copilot,
+ externalAccounts,
+ externalLinks,
+ challenges,
+ skills,
+ stats,
+ lookupData,
+ badges,
+ meta,
+ tcAcademyCertifications,
+ tcAcademyCourses
+ } = this.props;
+
return (
({
challenges: state.members[ownProps.match.params.handle]
? state.members[ownProps.match.params.handle].userMarathons : null,
- achievements: state.profile.achievements,
copilot: state.profile.copilot,
- country: state.profile.country,
externalAccounts: state.profile.externalAccounts,
externalLinks: state.profile.externalLinks,
handleParam: ownProps.match.params.handle,
diff --git a/src/shared/utils/markdown.js b/src/shared/utils/markdown.js
index 0144420f58..9d33046561 100644
--- a/src/shared/utils/markdown.js
+++ b/src/shared/utils/markdown.js
@@ -96,11 +96,11 @@ const safeHtmlTags = [
'caption', 'col', 'colgroup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr',
// Forms and Interactive Elements
- 'button', 'fieldset', 'form', 'input', 'label', 'legend', 'meter', 'optgroup', 'option', 'output', 'progress',
+ 'button', 'fieldset', 'form', 'input', 'label', 'legend', 'meter', 'optgroup', 'option', 'output', 'progress',
'select', 'textarea',
// Scripting and No-Scripting
- 'noscript'
+ 'noscript',
];
/**
@@ -193,8 +193,8 @@ function getProps(token, key) {
/**
* Check if the tag is safe to render.
- * @param {String} tag
- * @returns
+ * @param {String} tag
+ * @returns
*/
function checkForSafeTag(tag) {
return safeHtmlTags.includes(tag);
@@ -202,8 +202,8 @@ function checkForSafeTag(tag) {
/**
* Sanitize content
- * @param {String} content
- * @returns
+ * @param {String} content
+ * @returns
*/
function sanitizeContent(content) {
return xss(content);
@@ -276,7 +276,7 @@ function renderTokens(tokens, startFrom, md) {
} else if (level === 0) {
if (token.nesting === 1) {
output.push(React.createElement(
- checkForSafeTag(token.tag) ? token.tag : "div",
+ checkForSafeTag(token.tag) ? token.tag : 'div',
getProps(token, pos),
renderTokens(tokens, 1 + pos, md),
));
@@ -296,11 +296,11 @@ function renderTokens(tokens, startFrom, md) {
}
props = normalizeProps(props);
if (selfClosing) {
- output.push(React.createElement(checkForSafeTag(tag) ? tag : "div", { key: pos, ...props }));
+ output.push(React.createElement(checkForSafeTag(tag) ? tag : 'div', { key: pos, ...props }));
} else {
level += 1;
output.push(React.createElement(
- checkForSafeTag(tag) ? tag : "div",
+ checkForSafeTag(tag) ? tag : 'div',
{ key: pos, ...props },
renderTokens(tokens, pos + 1, md),
));
From d35c1ff44e2f52783cd90fe8be5a5fc16971faa8 Mon Sep 17 00:00:00 2001
From: Hentry Martin
Date: Tue, 14 Jan 2025 23:06:30 +0100
Subject: [PATCH 04/11] fix: lint
---
src/shared/containers/Profile.jsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shared/containers/Profile.jsx b/src/shared/containers/Profile.jsx
index d3f91eb194..cbc047eecd 100644
--- a/src/shared/containers/Profile.jsx
+++ b/src/shared/containers/Profile.jsx
@@ -146,7 +146,7 @@ class ProfileContainer extends React.Component {
badges,
meta,
tcAcademyCertifications,
- tcAcademyCourses
+ tcAcademyCourses,
} = this.props;
return (
From 1eff28dd3ef7263b8e59e28c3c7c7f64882b37cc Mon Sep 17 00:00:00 2001
From: Hentry Martin
Date: Wed, 15 Jan 2025 21:21:58 +0100
Subject: [PATCH 05/11] fix: unit tests
---
src/shared/utils/markdown.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/shared/utils/markdown.js b/src/shared/utils/markdown.js
index 9d33046561..e0e02f0b91 100644
--- a/src/shared/utils/markdown.js
+++ b/src/shared/utils/markdown.js
@@ -83,7 +83,7 @@ const safeHtmlTags = [
'address', 'article', 'aside', 'footer', 'header', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'main', 'nav', 'section',
// Text Content
- 'blockquote', 'dd', 'div', 'dl', 'dt', 'figcaption', 'figure', 'hr', 'li', 'ol', 'p', 'pre', 'ul',
+ 'blockquote', 'dd', 'div', 'dl', 'dt', 'figcaption', 'figure', 'hr', 'li', 'ol', 'p', 'pre', 'ul', 'big', 'tt', 'del', 'strike', 'ins',
// Inline Text Semantics
'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'code', 'data', 'dfn', 'em', 'i', 'kbd', 'mark', 'q', 'rp', 'rt',
@@ -101,6 +101,9 @@ const safeHtmlTags = [
// Scripting and No-Scripting
'noscript',
+
+ // Custom tags
+ 'ThemedButton',
];
/**
From 95230a6f56c275f329680006fb4f6cc1385661b6 Mon Sep 17 00:00:00 2001
From: Hentry Martin
Date: Wed, 15 Jan 2025 21:36:06 +0100
Subject: [PATCH 06/11] fix: removed password protection feature from
contentful
---
.../Contentful/PasswordScreen/index.jsx | 110 ------------------
.../Contentful/PasswordScreen/style.scss | 51 --------
src/shared/components/Contentful/Route.jsx | 32 ++---
3 files changed, 9 insertions(+), 184 deletions(-)
delete mode 100644 src/shared/components/Contentful/PasswordScreen/index.jsx
delete mode 100644 src/shared/components/Contentful/PasswordScreen/style.scss
diff --git a/src/shared/components/Contentful/PasswordScreen/index.jsx b/src/shared/components/Contentful/PasswordScreen/index.jsx
deleted file mode 100644
index c574520af5..0000000000
--- a/src/shared/components/Contentful/PasswordScreen/index.jsx
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * High order component that apply front-side password protection
- * before loading a Contentful Viewport. It uses sessionStorage for working.
- */
-import PT from 'prop-types';
-import React from 'react';
-import Viewport from 'components/Contentful/Viewport';
-import TextInput from 'components/GUIKit/TextInput';
-
-import './style.scss';
-
-export default class PasswordScreen extends React.Component {
- state = {};
-
- constructor(props) {
- super(props);
-
- this.onSubmit = this.onSubmit.bind(this);
- this.onPasswordInput = this.onPasswordInput.bind(this);
- }
-
- onSubmit() {
- const { password } = this.props;
- this.setState((state) => {
- const { inputVal } = state;
- return {
- authorized: password === inputVal,
- errorMsg: password === inputVal ? '' : 'Password incorrect',
- };
- });
- }
-
- onPasswordInput(inputVal) {
- const update = {
- inputVal,
- };
- if (!inputVal) update.errorMsg = '';
- this.setState(update);
- }
-
- render() {
- const {
- authorized, errorMsg, inputVal,
- } = this.state;
- const {
- viewPortId, preview, spaceName, environment, baseUrl, title, btnText, content,
- } = this.props;
- return authorized ? (
-
- ) : (
-
-
-
{title || 'GET ACCESS WITH PASSWORD'}
-
Please enter the password you were provided
-
this.onPasswordInput(val)}
- errorMsg={errorMsg}
- required
- type="password"
- onEnterKey={this.onSubmit}
- />
-
-
-
-
- {
- content ? (
-
- ) : null
- }
-
- );
- }
-}
-
-PasswordScreen.defaultProps = {
- preview: false,
- spaceName: null,
- environment: null,
- baseUrl: '',
- title: 'GET ACCESS WITH PASSWORD',
- btnText: 'SUBMIT',
- content: null,
-};
-
-PasswordScreen.propTypes = {
- password: PT.string.isRequired,
- viewPortId: PT.string.isRequired,
- preview: PT.bool,
- spaceName: PT.string,
- environment: PT.string,
- baseUrl: PT.string,
- title: PT.string,
- btnText: PT.string,
- content: PT.shape(),
-};
diff --git a/src/shared/components/Contentful/PasswordScreen/style.scss b/src/shared/components/Contentful/PasswordScreen/style.scss
deleted file mode 100644
index 74d6ddfd05..0000000000
--- a/src/shared/components/Contentful/PasswordScreen/style.scss
+++ /dev/null
@@ -1,51 +0,0 @@
-@import "~styles/mixins";
-@import "~components/Contentful/default";
-@import "~components/GUIKit/Assets/Styles/default";
-
-.wrapper {
- background-color: #e9e9e9;
- padding: 86px 0 121px 0;
- min-height: 100vh;
-
- .container {
- text-align: center;
- border-radius: 10px;
- max-width: 544px;
- max-height: 371px;
- margin: 0 auto;
- padding: 31px 65px;
- background-color: #fff;
-
- @include gui-kit-headers;
- @include gui-kit-content;
-
- h4 {
- margin-bottom: 5px;
- }
-
- .hint {
- font-size: 14px;
- margin-bottom: 30px;
- }
-
- .cta {
- margin: 50px auto 29px auto;
- }
-
- .submit {
- outline: none;
-
- @include primary-green;
- @include md;
-
- &:disabled,
- &:hover:disabled {
- background-color: #e9e9e9 !important;
- border: none !important;
- text-decoration: none !important;
- color: #fafafb !important;
- box-shadow: none !important;
- }
- }
- }
-}
diff --git a/src/shared/components/Contentful/Route.jsx b/src/shared/components/Contentful/Route.jsx
index 4b88d43585..2d1996b52b 100644
--- a/src/shared/components/Contentful/Route.jsx
+++ b/src/shared/components/Contentful/Route.jsx
@@ -12,7 +12,6 @@ import PT from 'prop-types';
import React from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import Viewport from 'components/Contentful/Viewport';
-import PasswordScreen from 'components/Contentful/PasswordScreen';
import { isomorphy, config } from 'topcoder-react-utils';
import cookies from 'browser-cookies';
import { removeTrailingSlash } from 'utils/url';
@@ -57,28 +56,15 @@ function ChildRoutesLoader(props) {
{
// eslint-disable-next-line no-nested-ternary
fields.viewport
- ? (!fields.password ? (
-
- ) : (
-
- )
- ) :
+ ? (
+
+ ) :
}
)}
From 98a38bfa8c7d12eb301e39da33a3296f4dda1356 Mon Sep 17 00:00:00 2001
From: Hentry Martin
Date: Wed, 15 Jan 2025 22:00:30 +0100
Subject: [PATCH 07/11] fix: lint
---
src/shared/components/Contentful/Route.jsx | 16 ++++++++--------
src/shared/utils/markdown.js | 2 +-
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/shared/components/Contentful/Route.jsx b/src/shared/components/Contentful/Route.jsx
index 2d1996b52b..0d9dccaf47 100644
--- a/src/shared/components/Contentful/Route.jsx
+++ b/src/shared/components/Contentful/Route.jsx
@@ -57,14 +57,14 @@ function ChildRoutesLoader(props) {
// eslint-disable-next-line no-nested-ternary
fields.viewport
? (
-
- ) :
+
+ ) :
}
)}
diff --git a/src/shared/utils/markdown.js b/src/shared/utils/markdown.js
index e0e02f0b91..e9afd6a9ea 100644
--- a/src/shared/utils/markdown.js
+++ b/src/shared/utils/markdown.js
@@ -103,7 +103,7 @@ const safeHtmlTags = [
'noscript',
// Custom tags
- 'ThemedButton',
+ 'Button',
];
/**
From 549e21cd70158661144d6c096505de885b675366 Mon Sep 17 00:00:00 2001
From: Hentry Martin
Date: Wed, 15 Jan 2025 22:11:44 +0100
Subject: [PATCH 08/11] fix: unit test
---
src/shared/utils/markdown.js | 56 ++++++++++++++++++------------------
1 file changed, 28 insertions(+), 28 deletions(-)
diff --git a/src/shared/utils/markdown.js b/src/shared/utils/markdown.js
index e9afd6a9ea..bde95592a4 100644
--- a/src/shared/utils/markdown.js
+++ b/src/shared/utils/markdown.js
@@ -78,34 +78,6 @@ const buttonThemes = {
bs,
};
-const safeHtmlTags = [
- // Content Sectioning
- 'address', 'article', 'aside', 'footer', 'header', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'main', 'nav', 'section',
-
- // Text Content
- 'blockquote', 'dd', 'div', 'dl', 'dt', 'figcaption', 'figure', 'hr', 'li', 'ol', 'p', 'pre', 'ul', 'big', 'tt', 'del', 'strike', 'ins',
-
- // Inline Text Semantics
- 'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'code', 'data', 'dfn', 'em', 'i', 'kbd', 'mark', 'q', 'rp', 'rt',
- 'ruby', 's', 'samp', 'small', 'span', 'strong', 'sub', 'sup', 'time', 'u', 'var', 'wbr',
-
- // Image and Multimedia
- 'img', 'audio', 'video', 'source', 'track', 'picture',
-
- // Table Content
- 'caption', 'col', 'colgroup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr',
-
- // Forms and Interactive Elements
- 'button', 'fieldset', 'form', 'input', 'label', 'legend', 'meter', 'optgroup', 'option', 'output', 'progress',
- 'select', 'textarea',
-
- // Scripting and No-Scripting
- 'noscript',
-
- // Custom tags
- 'Button',
-];
-
/**
* Add new Custom Components here.
*
@@ -162,6 +134,34 @@ const customComponents = {
MMLeaderboard: attrs => ({ type: MMLeaderboard, props: attrs }),
};
+const safeHtmlTags = [
+ // Content Sectioning
+ 'address', 'article', 'aside', 'footer', 'header', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'main', 'nav', 'section',
+
+ // Text Content
+ 'blockquote', 'dd', 'div', 'dl', 'dt', 'figcaption', 'figure', 'hr', 'li', 'ol', 'p', 'pre', 'ul', 'big', 'tt', 'del', 'strike', 'ins',
+
+ // Inline Text Semantics
+ 'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'code', 'data', 'dfn', 'em', 'i', 'kbd', 'mark', 'q', 'rp', 'rt',
+ 'ruby', 's', 'samp', 'small', 'span', 'strong', 'sub', 'sup', 'time', 'u', 'var', 'wbr',
+
+ // Image and Multimedia
+ 'img', 'audio', 'video', 'source', 'track', 'picture',
+
+ // Table Content
+ 'caption', 'col', 'colgroup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr',
+
+ // Forms and Interactive Elements
+ 'button', 'fieldset', 'form', 'input', 'label', 'legend', 'meter', 'optgroup', 'option', 'output', 'progress',
+ 'select', 'textarea',
+
+ // Scripting and No-Scripting
+ 'noscript',
+
+ // Custom tags
+ ...Object.keys(customTags),
+];
+
/**
* The following functions are only used internally and should not need to be
* changed for new components.
From 52aaa6faabb604aea2e169bf104e86db9a2aafe9 Mon Sep 17 00:00:00 2001
From: Hentry Martin
Date: Wed, 15 Jan 2025 22:20:56 +0100
Subject: [PATCH 09/11] fix: unit test
---
src/shared/utils/markdown.js | 31 ++++---------------------------
1 file changed, 4 insertions(+), 27 deletions(-)
diff --git a/src/shared/utils/markdown.js b/src/shared/utils/markdown.js
index bde95592a4..1b23da60d2 100644
--- a/src/shared/utils/markdown.js
+++ b/src/shared/utils/markdown.js
@@ -134,32 +134,9 @@ const customComponents = {
MMLeaderboard: attrs => ({ type: MMLeaderboard, props: attrs }),
};
-const safeHtmlTags = [
- // Content Sectioning
- 'address', 'article', 'aside', 'footer', 'header', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'main', 'nav', 'section',
-
- // Text Content
- 'blockquote', 'dd', 'div', 'dl', 'dt', 'figcaption', 'figure', 'hr', 'li', 'ol', 'p', 'pre', 'ul', 'big', 'tt', 'del', 'strike', 'ins',
-
- // Inline Text Semantics
- 'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'code', 'data', 'dfn', 'em', 'i', 'kbd', 'mark', 'q', 'rp', 'rt',
- 'ruby', 's', 'samp', 'small', 'span', 'strong', 'sub', 'sup', 'time', 'u', 'var', 'wbr',
-
- // Image and Multimedia
- 'img', 'audio', 'video', 'source', 'track', 'picture',
-
- // Table Content
- 'caption', 'col', 'colgroup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr',
-
- // Forms and Interactive Elements
- 'button', 'fieldset', 'form', 'input', 'label', 'legend', 'meter', 'optgroup', 'option', 'output', 'progress',
- 'select', 'textarea',
-
- // Scripting and No-Scripting
- 'noscript',
-
- // Custom tags
- ...Object.keys(customTags),
+const unsafeHtmlTags = [
+ 'script', 'style', 'iframe', 'object', 'embed', 'applet', 'base',
+ 'form', 'meta', 'frame', 'frameset', 'marquee', 'svg',
];
/**
@@ -200,7 +177,7 @@ function getProps(token, key) {
* @returns
*/
function checkForSafeTag(tag) {
- return safeHtmlTags.includes(tag);
+ return !unsafeHtmlTags.includes(tag);
}
/**
From 29655d32d09eb826ba991683511e70638e7c87c6 Mon Sep 17 00:00:00 2001
From: Hentry Martin
Date: Wed, 15 Jan 2025 22:37:55 +0100
Subject: [PATCH 10/11] fix: unit test
---
src/shared/utils/markdown.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shared/utils/markdown.js b/src/shared/utils/markdown.js
index 1b23da60d2..f7168349f6 100644
--- a/src/shared/utils/markdown.js
+++ b/src/shared/utils/markdown.js
@@ -208,7 +208,7 @@ function renderToken(tokens, index, md) {
return renderTokens(token.children, 0, md);
/* eslint-enable no-use-before-define */
case 'text':
- return sanitizeContent(token.content);
+ return token.content;
case 'fence':
return Highlighter({
codeString: token.content,
From e574f3c2790d46872c54e19d7f1693bd2c1b78bc Mon Sep 17 00:00:00 2001
From: Hentry Martin
Date: Wed, 15 Jan 2025 22:46:27 +0100
Subject: [PATCH 11/11] fix: unit test
---
__tests__/shared/utils/__snapshots__/markdown.js.snap | 4 ++--
src/shared/utils/markdown.js | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/__tests__/shared/utils/__snapshots__/markdown.js.snap b/__tests__/shared/utils/__snapshots__/markdown.js.snap
index 449da8d15c..5dc7969857 100644
--- a/__tests__/shared/utils/__snapshots__/markdown.js.snap
+++ b/__tests__/shared/utils/__snapshots__/markdown.js.snap
@@ -1203,7 +1203,7 @@ Array [
A list item with a code block:
- <code goes here>
+ <code>
@@ -1294,7 +1294,7 @@ end tell
ampersands and angle brackets. For example, this:
,
- <div class="footer">
+ <div>
© 2004 Foo Corporation
</div>
diff --git a/src/shared/utils/markdown.js b/src/shared/utils/markdown.js
index f7168349f6..1b23da60d2 100644
--- a/src/shared/utils/markdown.js
+++ b/src/shared/utils/markdown.js
@@ -208,7 +208,7 @@ function renderToken(tokens, index, md) {
return renderTokens(token.children, 0, md);
/* eslint-enable no-use-before-define */
case 'text':
- return token.content;
+ return sanitizeContent(token.content);
case 'fence':
return Highlighter({
codeString: token.content,