Skip to content

Commit

Permalink
fix: sanitizing social feed script (#189)
Browse files Browse the repository at this point in the history
  • Loading branch information
melniiv authored Aug 23, 2024
1 parent f0392c3 commit 088729e
Show file tree
Hide file tree
Showing 9 changed files with 44 additions and 23 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-helsinki-headless-cms",
"version": "1.0.0-alpha296",
"version": "1.0.0-alpha298",
"description": "React components for displaying Headless CMS content according to guidelines set by HDS",
"main": "cjs/index.js",
"module": "index.js",
Expand Down
3 changes: 2 additions & 1 deletion src/common/components/htmlToReact/HtmlToReact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import parse, {
import classNames from 'classnames';

import styles from './htmlToReact.module.scss';
import { isTrustedOrigin, validateTrustedOriginsFormat } from './utils';
import {
DefaultH2,
DefaultP,
IframeForEmbeddedMedia,
} from './replaceComponents';
import validateTrustedOriginsFormat from '../../../core/utils/validateTrustedOriginsFormat';
import isTrustedOrigin from '../../../core/utils/isTrustedOrigin';

const hasClassName = (domNode: Element, className: string) =>
domNode.attribs.class?.split(/\s+/)?.includes(className) ?? false;
Expand Down
2 changes: 0 additions & 2 deletions src/common/components/htmlToReact/utils/index.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/core/configProvider/configContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ export type Config = {
htmlSanitizer: {
allowedUnsafeTags: HtmlToReactProps['allowedUnsafeTags'];
trustedOrigins: HtmlToReactProps['trustedOrigins'];
allowUnsafeSocialMediaScript: boolean;
};
};

Expand Down
1 change: 0 additions & 1 deletion src/core/configProvider/defaultConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,5 @@ export const defaultConfig: Config = {
htmlSanitizer: {
allowedUnsafeTags: [],
trustedOrigins: [],
allowUnsafeSocialMediaScript: false,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ const Template: StoryFn<typeof SocialMediaFeedModule> = (args) => (
...defaultConfig,
htmlSanitizer: {
allowedUnsafeTags: [],
trustedOrigins: [],
allowUnsafeSocialMediaScript: true,
trustedOrigins: ['https://plugins.flockler.com'],
},
}}
>
Expand All @@ -36,6 +35,6 @@ const Template: StoryFn<typeof SocialMediaFeedModule> = (args) => (
</ConfigProvider>
);

export const ImageGalleryModuleDefault = {
export const SocialMediaFeedModuleDefault = {
render: Template,
};
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import React, { useLayoutEffect, useRef } from 'react';
import React, { useLayoutEffect, useMemo, useRef } from 'react';
import DOMPurify from 'isomorphic-dompurify';
import parse, { DOMNode } from 'html-react-parser';

import Text from '../../../common/components/text/Text';
import { useConfig } from '../../configProvider/useConfig';
import styles from '../pageModules.module.scss';
import isTrustedOrigin from '../../utils/isTrustedOrigin';

export interface SocialMediaFeedModuleProps {
anchor: string;
Expand All @@ -16,30 +19,52 @@ export function SocialMediaFeedModule({
script,
}: SocialMediaFeedModuleProps) {
const {
htmlSanitizer: { allowUnsafeSocialMediaScript },
htmlSanitizer: { trustedOrigins },
} = useConfig();

const scriptWrapperRef = useRef<HTMLDivElement>();

useLayoutEffect(() => {
if (allowUnsafeSocialMediaScript) {
if (scriptWrapperRef.current?.innerHTML) {
const range = document.createRange();
range.selectNode(scriptWrapperRef.current);
const documentFragment = range.createContextualFragment(script);
const documentFragment = range.createContextualFragment(
scriptWrapperRef.current.innerHTML,
);
scriptWrapperRef.current.innerHTML = '';
scriptWrapperRef.current.append(documentFragment);
}
}, [script, allowUnsafeSocialMediaScript]);
}, [scriptWrapperRef.current?.innerHTML]);

if (!script) return null;
const sanitizeScripts = (domNode: DOMNode) => {
if ('attribs' in domNode) {
if (
domNode.name === 'script' &&
!isTrustedOrigin(domNode.attribs.src, trustedOrigins)
) {
// eslint-disable-next-line no-console
console.warn(
'The unsafe social media feed script is not allowed. Please enable it in hcrc library configs.',
);
return <div />;
}
}

return domNode;
};

const clean = useMemo(
() =>
DOMPurify.sanitize(script, {
FORCE_BODY: true,
ADD_TAGS: ['script', 'div'],
}),
[script],
);

if (!allowUnsafeSocialMediaScript) {
// eslint-disable-next-line no-console
console.warn(
'The unsafe social media feed script is not allowed. Please enable it in hcrc library configs.',
);
return null;
}
const htmlReactParserOptions = {
replace: (domNode) => sanitizeScripts(domNode),
};

return (
<div id={anchor} className={styles.pageModuleWrapper}>
Expand All @@ -48,7 +73,7 @@ export function SocialMediaFeedModule({
{title}
</Text>
)}
<div ref={scriptWrapperRef} />
<div ref={scriptWrapperRef}>{parse(clean, htmlReactParserOptions)}</div>
</div>
);
}
File renamed without changes.

0 comments on commit 088729e

Please sign in to comment.