Skip to content

Commit 66d5b39

Browse files
committed
request #13278: Remove direct usage of the v-html directive in Vue apps
v-html usages is replaced by a safer by default alternative. The goals are multiple: * make it easier to do the right thing for the developers: besides telling Vue to use the plugin at the instantiation of the app, the new directive can be used directly. There is no need of defining a new computed properties to sanize the value which means less boilerplate code. * reduce the number of points to inspect: only the directive/plugin code (and potentially a custom config at the init of the Vue app) instead of all the usages of v-html and the computed props associated with them. Note this does not means v-dompurify-html should be used everywhere, the usages should be limited where there is a real need for it and no alternative (same as v-html). No functionnal change is expected. vue-eslint-parser has been rollbacked to version 5.x. The 6.x version is not yet compatible with eslint-plugin-vue [0] causing false positives. It seems that major versions of vue-eslint-parser and eslint-plugin-vue must be kept in sync. [0] vuejs/eslint-plugin-vue#807 Change-Id: Ibd599706cf3f6b19076841b4d7f330cab11e2e33
1 parent e165b91 commit 66d5b39

File tree

20 files changed

+86
-99
lines changed

20 files changed

+86
-99
lines changed

package-lock.json

+22-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"stylelint": "^9.9.0",
5555
"stylelint-config-property-sort-order-smacss": "^4.0.2",
5656
"stylelint-config-sass-guidelines": "^5.3.0",
57-
"vue-eslint-parser": "^6.0.3",
57+
"vue-eslint-parser": "^5.0.0",
5858
"vue-loader": "^15.4.2",
5959
"webpack": "^4.20.2",
6060
"webpack-assets-manifest": "^3.1.1",

plugins/create_test_env/scripts/call-me-back-burning-parrot/src/CallMeBack.vue

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
- Copyright (c) Enalean, 2018. All Rights Reserved.
2+
- Copyright (c) Enalean, 2018-Present. All Rights Reserved.
33
-
44
- This file is a part of Tuleap.
55
-
@@ -18,8 +18,7 @@
1818
-->
1919
<template>
2020
<div class="call-me-back tlp-dropdown">
21-
<!-- eslint-disable-next-line vue/no-v-html -->
22-
<div class="call-me-back-message" v-if="! dropdown_open && message" v-html="sanitized_message"></div>
21+
<div class="call-me-back-message" v-if="! dropdown_open && message" v-dompurify-html="message"></div>
2322
<button class="call-me-back-button tlp-button-primary tlp-button-large" ref="call_me_back_button">
2423
<i class="fa fa-phone"></i>
2524
</button>
@@ -85,7 +84,6 @@
8584
import { dropdown, datePicker } from "tlp";
8685
import { getCallMeBackMessage, askToBeCalledBack } from "../../call-me-back-rest-querier.js";
8786
import { DateTime } from "luxon";
88-
import { sanitize } from "dompurify";
8987

9088
export default {
9189
name: "CallMeBack",
@@ -103,9 +101,6 @@ export default {
103101
computed: {
104102
call_me_back_formatted_date() {
105103
return DateTime.fromISO(this.call_me_back_date).toLocaleString(DateTime.DATE_FULL);
106-
},
107-
sanitized_message() {
108-
return sanitize(this.message);
109104
}
110105
},
111106
mounted() {

plugins/create_test_env/scripts/call-me-back-burning-parrot/src/index.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright (c) Enalean, 2018. All Rights Reserved.
2+
* Copyright (c) Enalean, 2018-Present. All Rights Reserved.
33
*
44
* This file is a part of Tuleap.
55
*
@@ -18,12 +18,14 @@
1818
*/
1919

2020
import Vue from "vue";
21+
import VueDOMPurifyHTML from "vue-dompurify-html";
2122
import GetTextPlugin from "vue-gettext";
2223
import french_translations from "../../po/fr.po";
2324
import CallMeBack from "./CallMeBack.vue";
2425
import { Settings } from "luxon";
2526

2627
document.addEventListener("DOMContentLoaded", () => {
28+
Vue.use(VueDOMPurifyHTML);
2729
Vue.use(GetTextPlugin, {
2830
translations: {
2931
fr: french_translations.messages

plugins/create_test_env/scripts/call-me-back-flaming-parrot/src/CallMeBack.vue

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
- Copyright (c) Enalean, 2018. All Rights Reserved.
2+
- Copyright (c) Enalean, 2018-Present. All Rights Reserved.
33
-
44
- This file is a part of Tuleap.
55
-
@@ -18,8 +18,7 @@
1818
-->
1919
<template>
2020
<div class="call-me-back dropup" ref="dropdown">
21-
<!-- eslint-disable-next-line vue/no-v-html -->
22-
<div class="call-me-back-message" v-if="! dropdown_open && message" v-html="sanitized_message"></div>
21+
<div class="call-me-back-message" v-if="! dropdown_open && message" v-dompurify-html="message"></div>
2322
<button class="call-me-back-button dropdown-toggle" data-toggle="dropdown">
2423
<i class="fa fa-phone"></i>
2524
</button>
@@ -84,7 +83,6 @@
8483
<script>
8584
import { getCallMeBackMessage, askToBeCalledBack } from "../../call-me-back-rest-querier.js";
8685
import { DateTime } from "luxon";
87-
import { sanitize } from "dompurify";
8886
import jQuery from "jquery";
8987

9088
export default {
@@ -106,9 +104,6 @@ export default {
106104
computed: {
107105
call_me_back_formatted_date() {
108106
return DateTime.fromISO(this.call_me_back_date).toLocaleString(DateTime.DATE_FULL);
109-
},
110-
sanitized_message() {
111-
return sanitize(this.message);
112107
}
113108
},
114109
mounted() {

plugins/create_test_env/scripts/call-me-back-flaming-parrot/src/index.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright (c) Enalean, 2018. All Rights Reserved.
2+
* Copyright (c) Enalean, 2018-Present. All Rights Reserved.
33
*
44
* This file is a part of Tuleap.
55
*
@@ -18,12 +18,14 @@
1818
*/
1919

2020
import Vue from "vue";
21+
import VueDOMPurifyHTML from "vue-dompurify-html";
2122
import GetTextPlugin from "vue-gettext";
2223
import french_translations from "../../po/fr.po";
2324
import CallMeBack from "./CallMeBack.vue";
2425
import { Settings } from "luxon";
2526

2627
document.addEventListener("DOMContentLoaded", () => {
28+
Vue.use(VueDOMPurifyHTML);
2729
Vue.use(GetTextPlugin, {
2830
translations: {
2931
fr: french_translations.messages

plugins/create_test_env/scripts/package-lock.json

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/create_test_env/scripts/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
"license": "GPL-2.0+",
77
"private": true,
88
"dependencies": {
9-
"dompurify": "^1.0.10",
109
"luxon": "^0.5.3",
1110
"vue": "^2.5.17",
11+
"vue-dompurify-html": "^1.2.0",
1212
"vue-gettext": "^2.1.0"
1313
},
1414
"config": {

plugins/document/scripts/document/components/Folder/ItemDisplay/DisplayEmbeddedContent.vue

+3-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
<section class="tlp-pane">
3131
<div class="tlp-pane-container">
32-
<section class="tlp-pane-section" v-html="embedded_content"></section>
32+
<section class="tlp-pane-section" v-dompurify-html="embedded_content"></section>
3333
</div>
3434
</section>
3535

@@ -38,7 +38,6 @@
3838
</template>
3939

4040
<script>
41-
import dompurify from "dompurify";
4241
import DropdownButton from "../ActionsDropDown/DropdownButton.vue";
4342
import DropdownMenu from "../ActionsDropDown/DropdownMenu.vue";
4443
import UpdateItemButton from "../ActionsButton/UpdateItemButton.vue";
@@ -67,10 +66,10 @@ export default {
6766
},
6867
embedded_content() {
6968
if (!this.embedded_file.embedded_file_properties) {
70-
return;
69+
return "";
7170
}
7271

73-
return dompurify.sanitize(this.embedded_file.embedded_file_properties.content);
72+
return this.embedded_file.embedded_file_properties.content;
7473
}
7574
},
7675
mounted() {

plugins/document/scripts/document/components/Folder/QuickLook/QuickLookDocumentPreview.vue

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
- Copyright (c) Enalean, 2019. All Rights Reserved.
2+
- Copyright (c) Enalean, 2019-Present. All Rights Reserved.
33
-
44
- This file is a part of Tuleap.
55
-
@@ -18,8 +18,7 @@
1818
-
1919
-->
2020
<template>
21-
<!-- eslint-disable-next-line vue/no-v-html -->
22-
<div v-html="escaped_embedded_content"
21+
<div v-dompurify-html="item.embedded_file_properties.content"
2322
class="document-quick-look-embedded"
2423
v-if="is_embedded"
2524
></div>
@@ -89,7 +88,6 @@
8988
</div>
9089
</template>
9190
<script>
92-
import dompurify from "dompurify";
9391
import { TYPE_EMBEDDED, TYPE_FOLDER } from "../../../constants.js";
9492
import IconQuicklookFolder from "../../svg-icons/IconQuicklookFolder.vue";
9593
import IconQuicklookDropIntoFolder from "../../svg-icons/IconQuicklookDropIntoFolder.vue";
@@ -115,11 +113,11 @@ export default {
115113
is_embedded() {
116114
return this.item.type === TYPE_EMBEDDED;
117115
},
118-
escaped_embedded_content() {
116+
embedded_content() {
119117
if (!this.item.embedded_file_properties) {
120-
return;
118+
return "";
121119
}
122-
return dompurify.sanitize(this.item.embedded_file_properties.content);
120+
return this.item.embedded_file_properties.content;
123121
},
124122
is_a_folder() {
125123
return this.item.type === TYPE_FOLDER;

plugins/document/scripts/document/helpers/local-vue.js

+2
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@
2020

2121
import { createLocalVue } from "@vue/test-utils";
2222
import Vuex from "vuex";
23+
import VueDOMPurifyHTML from "vue-dompurify-html";
2324
import GettextPlugin from "vue-gettext";
2425
import VueRouter from "vue-router";
2526

2627
const localVue = createLocalVue();
2728
localVue.use(Vuex);
2829
localVue.use(VueRouter);
2930

31+
localVue.use(VueDOMPurifyHTML);
3032
localVue.use(GettextPlugin, {
3133
translations: {},
3234
silent: true

plugins/document/scripts/document/index.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) Enalean, 2018-2019. All Rights Reserved.
2+
* Copyright (c) Enalean, 2018-Present. All Rights Reserved.
33
*
44
* This file is a part of Tuleap.
55
*
@@ -19,6 +19,7 @@
1919

2020
import Vue from "vue";
2121
import GetTextPlugin from "vue-gettext";
22+
import VueDOMPurifyHTML from "vue-dompurify-html";
2223

2324
import french_translations from "./po/fr.po";
2425
import App from "./components/App.vue";
@@ -28,6 +29,7 @@ import moment from "moment";
2829
import "moment-timezone";
2930

3031
document.addEventListener("DOMContentLoaded", () => {
32+
Vue.use(VueDOMPurifyHTML);
3133
Vue.use(GetTextPlugin, {
3234
translations: {
3335
fr: french_translations.messages

plugins/document/scripts/package-lock.json

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/document/scripts/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
"license": "GPL-2.0+",
77
"private": true,
88
"dependencies": {
9-
"dompurify": "^1.0.9",
109
"moment": "^2.22.2",
1110
"moment-timezone": "^0.5.23",
1211
"phptomoment": "0.0.2",
1312
"pretty-bytes-es5": "^5.1.9",
1413
"pretty-kibibytes": "^4.0.4",
1514
"tus-js-client": "^1.5.2",
1615
"vue": "^2.5.17",
16+
"vue-dompurify-html": "^1.2.0",
1717
"vue-gettext": "^2.1.0",
1818
"vue-router": "^3.0.1",
1919
"vuex": "^3.0.1"

plugins/label/www/scripts/package-lock.json

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/label/www/scripts/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
"license": "GPL-2.0+",
77
"private": true,
88
"dependencies": {
9-
"dompurify": "^1.0.10",
109
"mustache": "^2.3.0",
1110
"vue": "^2.5.17",
11+
"vue-dompurify-html": "^1.2.0",
1212
"vue-gettext": "^2.1.0"
1313
},
1414
"devDependencies": {

0 commit comments

Comments
 (0)