Allowed markdown in footer of status page

Markdown support has been added using the marked module. To secure
against XSS attacks, DOMPurify is used to sanitize the generated HTML
before it is loaded on the page.

Signed-off-by: Matthew Nickson <mnickson@sidingsmedia.com>
pull/2570/head
Matthew Nickson 2 years ago
parent f3d3e064f8
commit 6bc0bd84af
No known key found for this signature in database
GPG Key ID: BF229DCFD4748E05

28
package-lock.json generated

@ -26,6 +26,7 @@
"compare-versions": "~3.6.0",
"compression": "~1.7.4",
"dayjs": "~1.11.5",
"dompurify": "^2.4.3",
"express": "~4.17.3",
"express-basic-auth": "~1.2.1",
"express-static-gzip": "~2.1.7",
@ -38,6 +39,7 @@
"jsonwebtoken": "~9.0.0",
"jwt-decode": "~3.1.2",
"limiter": "~2.1.0",
"marked": "^4.2.5",
"mqtt": "~4.3.7",
"mssql": "~8.1.4",
"mysql2": "~2.3.3",
@ -6499,6 +6501,11 @@
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/dompurify": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz",
"integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ=="
},
"node_modules/domutils": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
@ -12185,6 +12192,17 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/marked": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz",
"integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==",
"bin": {
"marked": "bin/marked.js"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/mathml-tag-names": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",
@ -22155,6 +22173,11 @@
"domelementtype": "^2.3.0"
}
},
"dompurify": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz",
"integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ=="
},
"domutils": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
@ -26299,6 +26322,11 @@
"integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
"dev": true
},
"marked": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz",
"integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ=="
},
"mathml-tag-names": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz",

@ -81,6 +81,7 @@
"compare-versions": "~3.6.0",
"compression": "~1.7.4",
"dayjs": "~1.11.5",
"dompurify": "^2.4.3",
"express": "~4.17.3",
"express-basic-auth": "~1.2.1",
"express-static-gzip": "~2.1.7",
@ -93,6 +94,7 @@
"jsonwebtoken": "~9.0.0",
"jwt-decode": "~3.1.2",
"limiter": "~2.1.0",
"marked": "^4.2.5",
"mqtt": "~4.3.7",
"mssql": "~8.1.4",
"mysql2": "~2.3.3",

@ -675,4 +675,5 @@ export default {
"General Monitor Type": "General Monitor Type",
"Passive Monitor Type": "Passive Monitor Type",
"Specific Monitor Type": "Specific Monitor Type",
markdownSupported: "Markdown syntax supported",
};

@ -26,6 +26,9 @@
<div class="my-3">
<label for="footer-text" class="form-label">{{ $t("Footer Text") }}</label>
<textarea id="footer-text" v-model="config.footerText" class="form-control"></textarea>
<div class="form-text">
{{ $t("markdownSupported") }}
</div>
</div>
<div class="my-3 form-check form-switch">
@ -279,7 +282,9 @@
<div class="custom-footer-text text-start">
<strong v-if="enableEditMode">{{ $t("Custom Footer") }}:</strong>
</div>
<Editable v-model="config.footerText" tag="div" :contenteditable="enableEditMode" :noNL="false" class="alert-heading p-2" />
<Editable v-if="enableEditMode" v-model="config.footerText" tag="div" :contenteditable="enableEditMode" :noNL="false" class="alert-heading p-2" />
<!-- eslint-disable-next-line vue/no-v-html-->
<div v-if="! enableEditMode" class="alert-heading p-2" v-html="footerHTML"></div>
<p v-if="config.showPoweredBy">
{{ $t("Powered by") }} <a target="_blank" rel="noopener noreferrer" href="https://github.com/louislam/uptime-kuma">{{ $t("Uptime Kuma" ) }}</a>
@ -310,6 +315,8 @@ import ImageCropUpload from "vue-image-crop-upload";
import { PrismEditor } from "vue-prism-editor";
import "vue-prism-editor/dist/prismeditor.min.css"; // import the styles somewhere
import { useToast } from "vue-toastification";
import { marked } from "marked";
import DOMPurify from "dompurify";
import Confirm from "../components/Confirm.vue";
import PublicGroupList from "../components/PublicGroupList.vue";
import MaintenanceTime from "../components/MaintenanceTime.vue";
@ -477,6 +484,9 @@ export default {
return this.overallStatus === STATUS_PAGE_MAINTENANCE;
},
footerHTML() {
return DOMPurify.sanitize(marked(this.config.footerText));
},
},
watch: {

Loading…
Cancel
Save