Skip to content

Commit 86fe8ea

Browse files
author
amazon-meaisiah
committed
Update vulnerable dependencies, simplify Markdown parsing
The `react-markdown` update was non-trivial, so I decided it'd be a better use of time to just replace it wholesale with Marked. Also, DOMPurify just happened to already exist, so adding it as a dependency doesn't actually bloat the bundle any. Also added a couple features: - GitHub Flavored Markdown is now supported - Headers in custom content fragments now include IDs prefixed with `header-`, so you can reference things like `# Section Header` via `#header-section-header`.
1 parent dcf8106 commit 86fe8ea

35 files changed

+640
-574
lines changed

dev-portal/package-lock.json

Lines changed: 48 additions & 324 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dev-portal/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@
33
"version": "4.0.4",
44
"private": true,
55
"dependencies": {
6-
"chart.js": "^2.7.2",
6+
"chart.js": "^2.9.4",
7+
"dompurify": "^2.2.8",
78
"front-matter": "^3.0.0",
89
"jwt-decode": "^2.2.0",
9-
"lodash": "^4.17.19",
10+
"lodash": "^4.17.21",
11+
"marked": "^2.0.4",
1012
"mobx": "^5.15.4",
1113
"mobx-react": "^6.2.2",
1214
"object-hash": "^2.0.3",
1315
"query-string": "^6.12.1",
1416
"react": "^16.8.4",
1517
"react-dom": "^16.8.4",
16-
"react-markdown": "^4.0.3",
1718
"react-router-dom": "^4.3.1",
1819
"semantic-ui-css": "^2.4.1",
1920
"semantic-ui-react": "^0.87.3",

dev-portal/src/components/SwaggerUiLayout.jsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import React from 'react'
4+
import React, { useMemo } from 'react'
55

66
// semantic-ui
77
import { Button, Header, Image, Container } from 'semantic-ui-react'
88

99
// markdown for external docs description
10-
import Markdown from 'react-markdown/with-html'
10+
import marked from 'marked'
11+
import DOMPurify from 'dompurify'
1112

1213
// services
1314
import { subscribe, unsubscribe } from 'services/api-catalog'
@@ -22,6 +23,15 @@ import { store } from 'services/state.js'
2223
// Create the plugin that provides our layout component
2324
export const SwaggerLayoutPlugin = () => ({ components: { InfoContainer: InfoReplacement } })
2425

26+
function Markdown ({ source }) {
27+
const rendered = useMemo(() => DOMPurify.sanitize(marked(source, {
28+
headerIds: false,
29+
silent: true
30+
})), [source])
31+
32+
return <div dangerouslySetInnerHTML={{ __html: rendered }} />
33+
}
34+
2535
// replaces the InfoContainer component
2636
// https://github.com/swagger-api/swagger-ui/blob/dd3afdc45656bda2a64ae6a7f9bdad006ea98149/src/core/components/layouts/base.jsx
2737

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import React from 'react'
4+
import React, { useLayoutEffect, useRef } from 'react'
5+
import ReactDOM from 'react-dom'
56

67
// react-router
78
import { Link } from 'react-router-dom'
@@ -11,7 +12,7 @@ import { observable } from 'mobx'
1112

1213
// markdown parsing
1314
import frontmatter from 'front-matter'
14-
import Markdown from 'react-markdown/with-html'
15+
import marked from 'marked'
1516

1617
export const fragments = observable({})
1718

@@ -22,8 +23,10 @@ export const loadFragments = () => {
2223
}
2324

2425
/**
25-
*
26-
* Pre-load the custom-content markdown, parses its frontmatter, and renders it as JSX. This method is asynchronous and doesn't actually return anything -- instead, it acts on a MobX Observable -- the fragment. The fragment is an object with a `jsx` property that maps to the rendered component, and any number of other properties collected from the front-matter.
26+
* Pre-load the custom-content markdown, parses its frontmatter, and renders it as JSX. This method
27+
* is asynchronous and doesn't actually return anything -- instead, it acts on a MobX Observable --
28+
* the fragment. The fragment is an object with a `jsx` property that maps to the rendered
29+
* component, and any number of other properties collected from the front-matter.
2730
*
2831
* @param {String} path Path to the file to load in. Should be a markdown file.
2932
* @param {String} fragment Name of the fragment. Determines where rendered data gets stored.
@@ -36,34 +39,61 @@ function loadHtml (path, fragment) {
3639

3740
window.fetch(path).then(response => response.text().then(text => {
3841
const parsedMarkdown = frontmatter(text)
42+
const html = marked(parsedMarkdown.body, {
43+
headerPrefix: 'header-',
44+
silent: true
45+
})
3946

4047
fragments[fragment] = {
41-
jsx: () => (
42-
<Markdown
43-
escapeHtml={false}
44-
source={parsedMarkdown.body}
45-
renderers={renderers}
46-
/>
47-
),
48+
jsx: () => <ShowHTML html={html} />,
4849
...parsedMarkdown.attributes
4950
}
5051
}))
5152
}
5253

53-
/**
54-
* Renderers is a map of node type to component.
55-
*
56-
* In this case, we only override links. Any time react-markdown tries to render a link, it'll render this component. Normal links will work, but the cause a full page reload. We don't want that, so we can replacing them with react-router Links. However, replacing external links with react-router Links causes them to not work at all. We don't want that either, so we attempt to determine if a link is external or not, and use `Link` or `a` appropriately.
57-
*/
58-
const renderers = {
59-
link: ({ href, ...props }) => {
60-
// if absolute url, use an `a` tag
61-
// https://stackoverflow.com/a/19709846/4060061
62-
if (/^(?:[a-z]+:)?\/\//i.test(href)) {
63-
return <a href={href} target='_blank' rel='noopener noreferrer' {...props} />
54+
function ShowHTML ({ html }) {
55+
/** @type {import("react").MutableRefObject<HTMLDivElement>} */
56+
const ref = useRef()
57+
58+
// Easier to do it here than to use a separate `useMemo` hook.
59+
useLayoutEffect(() => {
60+
// Normal links will work, but the cause a full page reload. We don't want that, so we replace
61+
// them with react-router Links. However, replacing external links with react-router Links
62+
// causes them to not work at all. We don't want that either, so we attempt to determine if a
63+
// link is external or not, and replace them as appropriate.
64+
65+
const mountPoints = []
66+
const links = ref.current.getElementsByTagName('a')
67+
68+
for (let i = 0; i < links.length; i++) {
69+
const link = links[i]
70+
// if absolute url, use an `a` tag
71+
// https://stackoverflow.com/a/19709846/4060061
72+
if (/^(?:[a-z]+:)?\/\//i.test(link.href)) {
73+
link.target = '_blank'
74+
link.rel = 'noopener noreferrer'
75+
} else {
76+
// Replace links with react-router-dom tags so that they route correctly
77+
const span = document.createElement('span')
78+
// If there's CSS, don't listen to it.
79+
span.style.setProperty('display', 'inline', 'important')
80+
ReactDOM.render(<Link
81+
to={link.href}
82+
target={link.target}
83+
dangerouslySetInnerHTML={{ __html: link.innerHTML }}
84+
/>, span)
85+
link.replaceWith(span)
86+
mountPoints.push(span)
87+
}
88+
}
89+
90+
// Gracefully unmount any mount points that were added
91+
return () => {
92+
mountPoints.forEach(elem => {
93+
ReactDOM.render(null, elem)
94+
})
6495
}
96+
}, [])
6597

66-
// replace links with react-router-dom tags so that they
67-
return <Link to={href} {...props} />
68-
}
98+
return <div ref={ref} dangerouslySetInnerHTML={{ __html: html }} />
6999
}

lambdas/cloudfront-security/node_modules/lodash/README.md

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lambdas/cloudfront-security/node_modules/lodash/_baseClone.js

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lambdas/cloudfront-security/node_modules/lodash/_baseOrderBy.js

Lines changed: 17 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lambdas/cloudfront-security/node_modules/lodash/_baseSet.js

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lambdas/cloudfront-security/node_modules/lodash/_baseSortedIndexBy.js

Lines changed: 7 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lambdas/cloudfront-security/node_modules/lodash/_baseTrim.js

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)