mirror of
https://github.com/cockpit-project/cockpit.git
synced 2026-11-03 21:49:50 -09:00
package.json: Switch to markdown-to-jsx
The PackageKit UpdateDetail signal provides markdown in the `update_text` and uses remarkable to parse the markdown contents. Remarkable however has not been updated since 6 years, additionally it requires us to use `dangerouslySetInnerHTML` which can lead to XSS issues. The npm ecosystem has two other markdown alternatives `react-markdown` and a `markdown-to-jsx`. The latter has zero dependencies while `react-markdown` has eleven and requires additional plugins like `rehype-external-links` to add a rel/target to external links. https://www.freedesktop.org/software/PackageKit/gtk-doc/Transaction.html https://github.com/jonschlinkert/remarkable/issues/438
This commit is contained in:
parent
6cab90c58b
commit
618473f951
5 changed files with 21 additions and 30 deletions
|
|
@ -25,6 +25,7 @@
|
||||||
"prefer-promise-reject-errors": ["error", { "allowEmptyReject": true }],
|
"prefer-promise-reject-errors": ["error", { "allowEmptyReject": true }],
|
||||||
"no-var": "error",
|
"no-var": "error",
|
||||||
"react/jsx-indent": ["error", 4],
|
"react/jsx-indent": ["error", 4],
|
||||||
|
"react/no-danger": "error",
|
||||||
"semi": ["error", "always", { "omitLastInOneLineBlock": true }],
|
"semi": ["error", "always", { "omitLastInOneLineBlock": true }],
|
||||||
|
|
||||||
"react-hooks/rules-of-hooks": "error",
|
"react-hooks/rules-of-hooks": "error",
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 271b14ba1169a06e6d11e4455411c22a10ae97f9
|
Subproject commit c0741b01b2dd77fc2ce598bbbcb1cfbe44cf4072
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
"prop-types": "15.8.1",
|
"prop-types": "15.8.1",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1",
|
||||||
"remarkable": "2.0.1",
|
"markdown-to-jsx": "9.10.3",
|
||||||
"throttle-debounce": "5.0.2",
|
"throttle-debounce": "5.0.2",
|
||||||
"uuid": "14.0.2",
|
"uuid": "14.0.2",
|
||||||
"@xterm/xterm": "6.0.0",
|
"@xterm/xterm": "6.0.0",
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ import {
|
||||||
SecurityIcon,
|
SecurityIcon,
|
||||||
} from "@patternfly/react-icons";
|
} from "@patternfly/react-icons";
|
||||||
import { TableText } from "@patternfly/react-table";
|
import { TableText } from "@patternfly/react-table";
|
||||||
import { Remarkable } from "remarkable";
|
import Markdown from "markdown-to-jsx";
|
||||||
|
|
||||||
import { AutoUpdates, getBackend } from "./autoupdates.jsx";
|
import { AutoUpdates, getBackend } from "./autoupdates.jsx";
|
||||||
import { KpatchSettings, KpatchStatus } from "./kpatch";
|
import { KpatchSettings, KpatchStatus } from "./kpatch";
|
||||||
|
|
@ -225,29 +225,19 @@ function isSafeUrl(href) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overrides the link_open function to apply our required HTML attributes
|
const markdownOptions = {
|
||||||
function customRemarkable() {
|
overrides: {
|
||||||
const remarkable = new Remarkable();
|
a: {
|
||||||
|
props: {
|
||||||
|
rel: "noopener noreferrer",
|
||||||
|
target: "_blank",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
forceInline: true,
|
||||||
|
};
|
||||||
|
|
||||||
remarkable.renderer.rules.link_open = function(tokens, idx) {
|
function updateItem(info, pkgNames, key) {
|
||||||
try {
|
|
||||||
const url = tokens[idx].href;
|
|
||||||
if (!isSafeUrl(url))
|
|
||||||
return "<a>";
|
|
||||||
|
|
||||||
const a = document.createElement("a");
|
|
||||||
a.setAttribute("href", url);
|
|
||||||
a.rel = "noopener noreferrer";
|
|
||||||
a.target = "_blank";
|
|
||||||
return a.outerHTML.replace("</a>", "");
|
|
||||||
} catch {
|
|
||||||
return "<a>";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return remarkable;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateItem(remarkable, info, pkgNames, key) {
|
|
||||||
const bug_urls = (info.bug_urls || []).filter(isSafeUrl);
|
const bug_urls = (info.bug_urls || []).filter(isSafeUrl);
|
||||||
const cve_urls = (info.cve_urls || []).filter(isSafeUrl);
|
const cve_urls = (info.cve_urls || []).filter(isSafeUrl);
|
||||||
const vendor_urls = (info.vendor_urls || []).filter(isSafeUrl);
|
const vendor_urls = (info.vendor_urls || []).filter(isSafeUrl);
|
||||||
|
|
@ -333,8 +323,8 @@ function updateItem(remarkable, info, pkgNames, key) {
|
||||||
descriptionFirstLine = cleanupChangelogLine(descriptionFirstLine);
|
descriptionFirstLine = cleanupChangelogLine(descriptionFirstLine);
|
||||||
let description;
|
let description;
|
||||||
if (info.markdown) {
|
if (info.markdown) {
|
||||||
descriptionFirstLine = <span dangerouslySetInnerHTML={{ __html: remarkable.render(descriptionFirstLine) }} />;
|
descriptionFirstLine = <Markdown options={markdownOptions}>{descriptionFirstLine}</Markdown>;
|
||||||
description = <div dangerouslySetInnerHTML={{ __html: remarkable.render(info.description) }} />;
|
description = <Markdown options={{ ...markdownOptions, forceInline: false }}>{info.description}</Markdown>;
|
||||||
} else {
|
} else {
|
||||||
description = <div className="changelog">{info.description}</div>;
|
description = <div className="changelog">{info.description}</div>;
|
||||||
}
|
}
|
||||||
|
|
@ -392,7 +382,6 @@ function updateItem(remarkable, info, pkgNames, key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpdatesList = ({ updates }) => {
|
const UpdatesList = ({ updates }) => {
|
||||||
const remarkable = customRemarkable();
|
|
||||||
const combined_updates = [];
|
const combined_updates = [];
|
||||||
|
|
||||||
// PackageKit doesn"t expose source package names, so group packages with the same version and changelog
|
// PackageKit doesn"t expose source package names, so group packages with the same version and changelog
|
||||||
|
|
@ -431,7 +420,7 @@ const UpdatesList = ({ updates }) => {
|
||||||
{ title: _("Severity"), props: { width: 15 } },
|
{ title: _("Severity"), props: { width: 15 } },
|
||||||
{ title: _("Details"), props: { width: 30 } },
|
{ title: _("Details"), props: { width: 30 } },
|
||||||
]}
|
]}
|
||||||
rows={combined_updates.map(update => updateItem(remarkable, update, packageNames[update.id].sort((a, b) => a.name > b.name), update.id))} />
|
rows={combined_updates.map(update => updateItem(update, packageNames[update.id].sort((a, b) => a.name > b.name), update.id))} />
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,8 +155,9 @@ cmd_runtime_tar() {
|
||||||
# special-case node_modules/iconv-lite/encodings/sbcs-data-generated.js, it's JS with binary strings in it
|
# special-case node_modules/iconv-lite/encodings/sbcs-data-generated.js, it's JS with binary strings in it
|
||||||
# and resolve/test/resolver/cup.coffee which is a single-byte test file
|
# and resolve/test/resolver/cup.coffee which is a single-byte test file
|
||||||
# Ubuntu 24.04's file (or at least not that in the GitHub actions runner) does not detect *.woff2 file type properly
|
# Ubuntu 24.04's file (or at least not that in the GitHub actions runner) does not detect *.woff2 file type properly
|
||||||
|
# markdown-to-jsx's js/cjs is so minified it gets recognized as "data", not JavaScript.
|
||||||
for pkg in $runtime_pkgs; do
|
for pkg in $runtime_pkgs; do
|
||||||
if find "$pkg" -type f -print0 |
|
if find "$pkg" -type f -not -path '*/markdown-to-jsx/dist/*.js' -not -path '*/markdown-to-jsx/dist/*.cjs' -print0 |
|
||||||
xargs -0 file --mime |
|
xargs -0 file --mime |
|
||||||
grep -Ev \
|
grep -Ev \
|
||||||
-e 'text/' \
|
-e 'text/' \
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue