diff --git a/package-lock.json b/package-lock.json index 7e88d1269..3efce2541 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index ebe305f92..fcda34371 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/languages/en.js b/src/languages/en.js index 8d07db6dc..5824ea4ab 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -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", }; diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue index 6cecf6682..6fbbe69a1 100644 --- a/src/pages/StatusPage.vue +++ b/src/pages/StatusPage.vue @@ -26,6 +26,9 @@
{{ $t("Powered by") }} {{ $t("Uptime Kuma" ) }} @@ -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: {