Skip to content

Commit

Permalink
feat: sanitize HTML in footer
Browse files Browse the repository at this point in the history
moved sanitize function into a separate file including some simple tests

closes AOEpeople#91
  • Loading branch information
d-koppenhagen authored and bastianccm committed Jan 11, 2022
1 parent 5a5928f commit e0113c4
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 17 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ To add a footnote to the footer, create a public folder in your application and
}
```

> The footnote information may include HTML like `<a href="https://foo.bar">My Link</a>` which will be sanitized.
### Add a help page with explanations
To add a help page, create a public folder in your application and put a `messages.json` in it.
```json
Expand Down Expand Up @@ -252,6 +254,8 @@ To add a help page, create a public folder in your application and put a `messag
}
```

> The information in `description`s for `rings` and `quadrants` as well as the `values` for `paragraphs` may include HTML like `<a href="https://foo.bar">My Link</a>` which will be sanitized.
> For more information see the source code of the [Messages Context](./src/context/MessagesContext/index.tsx).
## Development
Expand Down
3 changes: 2 additions & 1 deletion src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { assetUrl, getItemPageNames, isMobileViewport } from "../../config";
import { Item } from "../../model";
import "./footer.scss";
import { useMessages } from "../../context/MessagesContext";
import { sanitize } from "../../sanitize";

interface Props {
items: Item[];
Expand Down Expand Up @@ -34,7 +35,7 @@ const Footer: React.FC<Props> = ({ items, pageName }) => {
/>
}
>
<span className="footnote">{footerFootnote}</span>
<div className="footnote" dangerouslySetInnerHTML={sanitize(footerFootnote)}></div>
</Branding>
)}

Expand Down
20 changes: 4 additions & 16 deletions src/components/PageHelp/PageHelp.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import React from "react";
import sanitizeHtml from 'sanitize-html';
import HeroHeadline from "../HeroHeadline/HeroHeadline";
import Fadeable from "../Fadeable/Fadeable";
import SetTitle from "../SetTitle";
import { radarName } from "../../config";
import { useMessages } from "../../context/MessagesContext";
import { sanitize } from "../../sanitize";

interface Props {
leaving: boolean;
onLeave: () => void;
}

const sanitize = (dirty: string, options: sanitizeHtml.IOptions = {}) => ({
__html: sanitizeHtml(
dirty,
options
)
});

const PageHelp: React.FC<Props> = ({ leaving, onLeave }) => {
const { pageHelp } = useMessages();

Expand All @@ -34,12 +27,7 @@ const PageHelp: React.FC<Props> = ({ leaving, onLeave }) => {
<h3>{headline}</h3>
{values.map((element, index) => {
return (
<p key={index} dangerouslySetInnerHTML={sanitize(element, {
allowedTags: ['b', 'i', 'em', 'strong', 'a', 'ul', 'ol', 'li'],
allowedAttributes: {
'a': ['href', 'target']
},
})}></p>
<p key={index} dangerouslySetInnerHTML={sanitize(element)}></p>
)
})
}
Expand All @@ -50,7 +38,7 @@ const PageHelp: React.FC<Props> = ({ leaving, onLeave }) => {
<ul>
{quadrants.map(({ name, description }) => (
<li key={name}>
<strong>{name}:</strong> <span dangerouslySetInnerHTML={sanitize(description)}></span>
<strong>{name}:</strong> <span dangerouslySetInnerHTML={sanitize(description, {})}></span>
</li>
))}
</ul>
Expand All @@ -59,7 +47,7 @@ const PageHelp: React.FC<Props> = ({ leaving, onLeave }) => {
<ul>
{rings.map(({ name, description }) => (
<li key={name}>
<strong>{name}:</strong> <span dangerouslySetInnerHTML={sanitize(description)}></span>
<strong>{name}:</strong> <span dangerouslySetInnerHTML={sanitize(description, {})}></span>
</li>
))}
</ul>
Expand Down
20 changes: 20 additions & 0 deletions src/sanitize.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { sanitize } from "./sanitize";

describe("sanitize", () => {
it("should sanitize the string input to HTML output", () => {
let res = sanitize('foo');
expect(res.__html).toEqual("foo");
res = sanitize('<a href="https://example.org">Example.org</a>');
expect(res.__html).toEqual("<a href=\"https://example.org\">Example.org</a>");
});
it("should not sanitize not allowed tags", () => {
let res = sanitize('Before <iframe src="https://example.org"></iframe> After');
expect(res.__html).toEqual("Before After");
});
it("should accept options for rendering", () => {
let res = sanitize('<a href="https://example.org" target="_blank">Example.org</a>', { allowedAttributes: { a: ['href']}});
expect(res.__html).toEqual("<a href=\"https://example.org\">Example.org</a>");
});
});


15 changes: 15 additions & 0 deletions src/sanitize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import sanitizeHtml from 'sanitize-html';

const defaultSanitizeOptions = {
allowedTags: ['b', 'i', 'em', 'strong', 'a', 'ul', 'ol', 'li'],
allowedAttributes: {
'a': ['href', 'target']
}
}

export const sanitize = (dirty: string, options: sanitizeHtml.IOptions = defaultSanitizeOptions) => ({
__html: sanitizeHtml(
dirty,
options
)
});

0 comments on commit e0113c4

Please sign in to comment.