From a68ddcc6fe7d0161059af7ab2757f11e97678e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarda=20Kot=C4=9B=C5=A1ovec?= Date: Wed, 31 Jan 2024 11:05:46 +0100 Subject: [PATCH 1/6] pkp/pkp-lib#9421 new vue directive v-pkp-allowed-html with sigifnicantly stricter DOMPurify --- package-lock.json | 6 ++++++ package.json | 1 + src/directive/allowedHtml.js | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 src/directive/allowedHtml.js diff --git a/package-lock.json b/package-lock.json index 3054a4bf..32aa09a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "chart.js": "^4.3.3", "clone-deep": "^4.0.1", "debounce": "^1.2.0", + "dompurify": "^3.0.8", "dropzone-vue3": "^1.0.2", "element-resize-event": "^3.0.6", "floating-vue": "^2.0.0-beta.24", @@ -8428,6 +8429,11 @@ "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", "dev": true }, + "node_modules/dompurify": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.8.tgz", + "integrity": "sha512-b7uwreMYL2eZhrSCRC4ahLTeZcPZxSmYfmcQGXGkXiZSNW1X85v+SDM5KsWcpivIiUBH47Ji7NtyUdpLeF5JZQ==" + }, "node_modules/dotenv": { "version": "16.4.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", diff --git a/package.json b/package.json index 85dad536..8fb75b46 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "chart.js": "^4.3.3", "clone-deep": "^4.0.1", "debounce": "^1.2.0", + "dompurify": "^3.0.8", "dropzone-vue3": "^1.0.2", "element-resize-event": "^3.0.6", "floating-vue": "^2.0.0-beta.24", diff --git a/src/directive/allowedHtml.js b/src/directive/allowedHtml.js new file mode 100644 index 00000000..4040b2e6 --- /dev/null +++ b/src/directive/allowedHtml.js @@ -0,0 +1,40 @@ +import DOMPurify from 'dompurify'; + +const allowed_html = + 'a[href|target|title],em,strong,cite,code,ul,ol,li[class],dl,dt,dd,b,i,u,img[src|alt],sup,sub,br,p'; + +const ALLOWED_TAGS = []; +const ALLOWED_ATTR = []; + +allowed_html.split(',').forEach((tagWithAttribute) => { + const parts = tagWithAttribute.split('['); + const tag = parts[0]; + ALLOWED_TAGS.push(tag); + + if (parts.length > 1) { + const attributes = parts[1].substring(0, parts[1].length - 1).split('|'); + attributes.forEach((attribute) => ALLOWED_ATTR.push(attribute)); + } +}); + +// DOMPurify does not support defining tags along with attributes, its separate lists +// https://github.com/cure53/DOMPurify/issues/272 +const sanitizeConfig = { + ALLOWED_TAGS, + ALLOWED_ATTR, +}; + +export const allowedHtmlDirective = { + beforeMount(el, binding) { + // Sanitize the content before inserting it into the element + const cleanContent = DOMPurify.sanitize(binding.value, sanitizeConfig); + el.innerHTML = cleanContent; + }, + updated(el, binding) { + // Re-sanitize the content if the bound value changes + if (binding.value !== binding.oldValue) { + const cleanContent = DOMPurify.sanitize(binding.value, sanitizeConfig); + el.innerHTML = cleanContent; + } + }, +}; From 70891cf77f23aba0f2c827ced331ee7c4fec7144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarda=20Kot=C4=9B=C5=A1ovec?= Date: Wed, 31 Jan 2024 11:08:39 +0100 Subject: [PATCH 2/6] pkp/pkp-lib#9421 Switch all uses from v-html to v-pkp-allowed-html --- src/components/Container/SubmissionWizardPage.stories.js | 6 +++--- src/components/DateRange/DateRange.vue | 4 ++-- src/components/FileAttacher/FileAttacher.vue | 2 +- src/components/Form/FieldError.vue | 2 +- src/components/Form/FormGroup.vue | 2 +- src/components/Form/fields/FieldArchivingPn.vue | 6 +++--- src/components/Form/fields/FieldBaseAutosuggest.vue | 6 +++--- src/components/Form/fields/FieldColor.vue | 4 ++-- src/components/Form/fields/FieldHtml.vue | 4 ++-- src/components/Form/fields/FieldMetadataSetting.vue | 8 ++++---- src/components/Form/fields/FieldOptions.vue | 6 +++--- src/components/Form/fields/FieldPubId.vue | 4 ++-- src/components/Form/fields/FieldRadioInput.vue | 4 ++-- src/components/Form/fields/FieldRichTextarea.vue | 4 ++-- src/components/Form/fields/FieldSelect.vue | 4 ++-- src/components/Form/fields/FieldSelectIssue.vue | 6 +++--- src/components/Form/fields/FieldText.vue | 6 +++--- src/components/Form/fields/FieldTextarea.vue | 4 ++-- src/components/Form/fields/FieldUpload.vue | 4 ++-- src/components/Form/fields/FieldUploadImage.vue | 6 +++--- .../ListPanel/submissions/SubmissionsListItem.vue | 8 ++++---- src/components/ListPanel/users/SelectReviewerListItem.vue | 4 ++-- src/components/Modal/Dialog.vue | 2 +- src/components/Table/Table.vue | 2 +- src/components/Table/TableCell.vue | 2 +- src/docs/Component.vue | 4 ++-- src/docs/Page.vue | 2 +- src/docs/components/Modal/previews/PreviewModalSide.vue | 4 ++-- .../previews/PreviewSubmissionWizardPage.vue | 6 +++--- src/pages/submissions/SubmissionsTable.vue | 5 ++++- 30 files changed, 67 insertions(+), 64 deletions(-) diff --git a/src/components/Container/SubmissionWizardPage.stories.js b/src/components/Container/SubmissionWizardPage.stories.js index ecad4d14..c8eff906 100644 --- a/src/components/Container/SubmissionWizardPage.stories.js +++ b/src/components/Container/SubmissionWizardPage.stories.js @@ -86,7 +86,7 @@ const SubmissionWizardPageWithDataAndTemplate = {
@@ -262,7 +262,7 @@ const SubmissionWizardPageWithDataAndTemplate = {
{{ dateRangeLabel }} - +
diff --git a/src/components/FileAttacher/FileAttacher.vue b/src/components/FileAttacher/FileAttacher.vue index d085b0ab..aa98e67a 100644 --- a/src/components/FileAttacher/FileAttacher.vue +++ b/src/components/FileAttacher/FileAttacher.vue @@ -6,7 +6,7 @@ :key="key" >

{{ attacher.label }}

-

+

diff --git a/src/components/Form/FormGroup.vue b/src/components/Form/FormGroup.vue index 5528f30e..8e8f50f4 100644 --- a/src/components/Form/FormGroup.vue +++ b/src/components/Form/FormGroup.vue @@ -4,8 +4,8 @@ {{ label }}

diff --git a/src/components/Form/fields/FieldArchivingPn.vue b/src/components/Form/fields/FieldArchivingPn.vue index 8066b9e0..4662db2f 100644 --- a/src/components/Form/fields/FieldArchivingPn.vue +++ b/src/components/Form/fields/FieldArchivingPn.vue @@ -19,8 +19,8 @@
diff --git a/src/components/Form/fields/FieldMetadataSetting.vue b/src/components/Form/fields/FieldMetadataSetting.vue index d8e76c4c..ede2e8d0 100644 --- a/src/components/Form/fields/FieldMetadataSetting.vue +++ b/src/components/Form/fields/FieldMetadataSetting.vue @@ -6,8 +6,8 @@ diff --git a/src/components/Form/fields/FieldOptions.vue b/src/components/Form/fields/FieldOptions.vue index d60a3cb7..8c991492 100644 --- a/src/components/Form/fields/FieldOptions.vue +++ b/src/components/Form/fields/FieldOptions.vue @@ -21,8 +21,8 @@
- +
@@ -53,10 +53,10 @@