Skip to content

Commit

Permalink
request #13278: Remove direct usage of the v-html directive in Vue apps
Browse files Browse the repository at this point in the history
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
  • Loading branch information
LeSuisse committed Apr 18, 2019
1 parent e165b91 commit 66d5b39
Show file tree
Hide file tree
Showing 20 changed files with 86 additions and 99 deletions.
27 changes: 22 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -54,7 +54,7 @@
"stylelint": "^9.9.0",
"stylelint-config-property-sort-order-smacss": "^4.0.2",
"stylelint-config-sass-guidelines": "^5.3.0",
"vue-eslint-parser": "^6.0.3",
"vue-eslint-parser": "^5.0.0",
"vue-loader": "^15.4.2",
"webpack": "^4.20.2",
"webpack-assets-manifest": "^3.1.1",
Expand Down
@@ -1,5 +1,5 @@
<!--
- Copyright (c) Enalean, 2018. All Rights Reserved.
- Copyright (c) Enalean, 2018-Present. All Rights Reserved.
-
- This file is a part of Tuleap.
-
Expand All @@ -18,8 +18,7 @@
-->
<template>
<div class="call-me-back tlp-dropdown">
<!-- eslint-disable-next-line vue/no-v-html -->
<div class="call-me-back-message" v-if="! dropdown_open && message" v-html="sanitized_message"></div>
<div class="call-me-back-message" v-if="! dropdown_open && message" v-dompurify-html="message"></div>
<button class="call-me-back-button tlp-button-primary tlp-button-large" ref="call_me_back_button">
<i class="fa fa-phone"></i>
</button>
Expand Down Expand Up @@ -85,7 +84,6 @@
import { dropdown, datePicker } from "tlp";
import { getCallMeBackMessage, askToBeCalledBack } from "../../call-me-back-rest-querier.js";
import { DateTime } from "luxon";
import { sanitize } from "dompurify";
export default {
name: "CallMeBack",
Expand All @@ -103,9 +101,6 @@ export default {
computed: {
call_me_back_formatted_date() {
return DateTime.fromISO(this.call_me_back_date).toLocaleString(DateTime.DATE_FULL);
},
sanitized_message() {
return sanitize(this.message);
}
},
mounted() {
Expand Down
@@ -1,5 +1,5 @@
/**
* Copyright (c) Enalean, 2018. All Rights Reserved.
* Copyright (c) Enalean, 2018-Present. All Rights Reserved.
*
* This file is a part of Tuleap.
*
Expand All @@ -18,12 +18,14 @@
*/

import Vue from "vue";
import VueDOMPurifyHTML from "vue-dompurify-html";
import GetTextPlugin from "vue-gettext";
import french_translations from "../../po/fr.po";
import CallMeBack from "./CallMeBack.vue";
import { Settings } from "luxon";

document.addEventListener("DOMContentLoaded", () => {
Vue.use(VueDOMPurifyHTML);
Vue.use(GetTextPlugin, {
translations: {
fr: french_translations.messages
Expand Down
@@ -1,5 +1,5 @@
<!--
- Copyright (c) Enalean, 2018. All Rights Reserved.
- Copyright (c) Enalean, 2018-Present. All Rights Reserved.
-
- This file is a part of Tuleap.
-
Expand All @@ -18,8 +18,7 @@
-->
<template>
<div class="call-me-back dropup" ref="dropdown">
<!-- eslint-disable-next-line vue/no-v-html -->
<div class="call-me-back-message" v-if="! dropdown_open && message" v-html="sanitized_message"></div>
<div class="call-me-back-message" v-if="! dropdown_open && message" v-dompurify-html="message"></div>
<button class="call-me-back-button dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-phone"></i>
</button>
Expand Down Expand Up @@ -84,7 +83,6 @@
<script>
import { getCallMeBackMessage, askToBeCalledBack } from "../../call-me-back-rest-querier.js";
import { DateTime } from "luxon";
import { sanitize } from "dompurify";
import jQuery from "jquery";
export default {
Expand All @@ -106,9 +104,6 @@ export default {
computed: {
call_me_back_formatted_date() {
return DateTime.fromISO(this.call_me_back_date).toLocaleString(DateTime.DATE_FULL);
},
sanitized_message() {
return sanitize(this.message);
}
},
mounted() {
Expand Down
@@ -1,5 +1,5 @@
/**
* Copyright (c) Enalean, 2018. All Rights Reserved.
* Copyright (c) Enalean, 2018-Present. All Rights Reserved.
*
* This file is a part of Tuleap.
*
Expand All @@ -18,12 +18,14 @@
*/

import Vue from "vue";
import VueDOMPurifyHTML from "vue-dompurify-html";
import GetTextPlugin from "vue-gettext";
import french_translations from "../../po/fr.po";
import CallMeBack from "./CallMeBack.vue";
import { Settings } from "luxon";

document.addEventListener("DOMContentLoaded", () => {
Vue.use(VueDOMPurifyHTML);
Vue.use(GetTextPlugin, {
translations: {
fr: french_translations.messages
Expand Down
8 changes: 8 additions & 0 deletions plugins/create_test_env/scripts/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion plugins/create_test_env/scripts/package.json
Expand Up @@ -6,9 +6,9 @@
"license": "GPL-2.0+",
"private": true,
"dependencies": {
"dompurify": "^1.0.10",
"luxon": "^0.5.3",
"vue": "^2.5.17",
"vue-dompurify-html": "^1.2.0",
"vue-gettext": "^2.1.0"
},
"config": {
Expand Down
Expand Up @@ -29,7 +29,7 @@

<section class="tlp-pane">
<div class="tlp-pane-container">
<section class="tlp-pane-section" v-html="embedded_content"></section>
<section class="tlp-pane-section" v-dompurify-html="embedded_content"></section>
</div>
</section>

Expand All @@ -38,7 +38,6 @@
</template>

<script>
import dompurify from "dompurify";
import DropdownButton from "../ActionsDropDown/DropdownButton.vue";
import DropdownMenu from "../ActionsDropDown/DropdownMenu.vue";
import UpdateItemButton from "../ActionsButton/UpdateItemButton.vue";
Expand Down Expand Up @@ -67,10 +66,10 @@ export default {
},
embedded_content() {
if (!this.embedded_file.embedded_file_properties) {
return;
return "";
}
return dompurify.sanitize(this.embedded_file.embedded_file_properties.content);
return this.embedded_file.embedded_file_properties.content;
}
},
mounted() {
Expand Down
@@ -1,5 +1,5 @@
<!--
- Copyright (c) Enalean, 2019. All Rights Reserved.
- Copyright (c) Enalean, 2019-Present. All Rights Reserved.
-
- This file is a part of Tuleap.
-
Expand All @@ -18,8 +18,7 @@
-
-->
<template>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-html="escaped_embedded_content"
<div v-dompurify-html="item.embedded_file_properties.content"
class="document-quick-look-embedded"
v-if="is_embedded"
></div>
Expand Down Expand Up @@ -89,7 +88,6 @@
</div>
</template>
<script>
import dompurify from "dompurify";
import { TYPE_EMBEDDED, TYPE_FOLDER } from "../../../constants.js";
import IconQuicklookFolder from "../../svg-icons/IconQuicklookFolder.vue";
import IconQuicklookDropIntoFolder from "../../svg-icons/IconQuicklookDropIntoFolder.vue";
Expand All @@ -115,11 +113,11 @@ export default {
is_embedded() {
return this.item.type === TYPE_EMBEDDED;
},
escaped_embedded_content() {
embedded_content() {
if (!this.item.embedded_file_properties) {
return;
return "";
}
return dompurify.sanitize(this.item.embedded_file_properties.content);
return this.item.embedded_file_properties.content;
},
is_a_folder() {
return this.item.type === TYPE_FOLDER;
Expand Down
2 changes: 2 additions & 0 deletions plugins/document/scripts/document/helpers/local-vue.js
Expand Up @@ -20,13 +20,15 @@

import { createLocalVue } from "@vue/test-utils";
import Vuex from "vuex";
import VueDOMPurifyHTML from "vue-dompurify-html";
import GettextPlugin from "vue-gettext";
import VueRouter from "vue-router";

const localVue = createLocalVue();
localVue.use(Vuex);
localVue.use(VueRouter);

localVue.use(VueDOMPurifyHTML);
localVue.use(GettextPlugin, {
translations: {},
silent: true
Expand Down
4 changes: 3 additions & 1 deletion plugins/document/scripts/document/index.js
@@ -1,5 +1,5 @@
/*
* Copyright (c) Enalean, 2018-2019. All Rights Reserved.
* Copyright (c) Enalean, 2018-Present. All Rights Reserved.
*
* This file is a part of Tuleap.
*
Expand All @@ -19,6 +19,7 @@

import Vue from "vue";
import GetTextPlugin from "vue-gettext";
import VueDOMPurifyHTML from "vue-dompurify-html";

import french_translations from "./po/fr.po";
import App from "./components/App.vue";
Expand All @@ -28,6 +29,7 @@ import moment from "moment";
import "moment-timezone";

document.addEventListener("DOMContentLoaded", () => {
Vue.use(VueDOMPurifyHTML);
Vue.use(GetTextPlugin, {
translations: {
fr: french_translations.messages
Expand Down
8 changes: 8 additions & 0 deletions plugins/document/scripts/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion plugins/document/scripts/package.json
Expand Up @@ -6,14 +6,14 @@
"license": "GPL-2.0+",
"private": true,
"dependencies": {
"dompurify": "^1.0.9",
"moment": "^2.22.2",
"moment-timezone": "^0.5.23",
"phptomoment": "0.0.2",
"pretty-bytes-es5": "^5.1.9",
"pretty-kibibytes": "^4.0.4",
"tus-js-client": "^1.5.2",
"vue": "^2.5.17",
"vue-dompurify-html": "^1.2.0",
"vue-gettext": "^2.1.0",
"vue-router": "^3.0.1",
"vuex": "^3.0.1"
Expand Down
8 changes: 8 additions & 0 deletions plugins/label/www/scripts/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion plugins/label/www/scripts/package.json
Expand Up @@ -6,9 +6,9 @@
"license": "GPL-2.0+",
"private": true,
"dependencies": {
"dompurify": "^1.0.10",
"mustache": "^2.3.0",
"vue": "^2.5.17",
"vue-dompurify-html": "^1.2.0",
"vue-gettext": "^2.1.0"
},
"devDependencies": {
Expand Down

0 comments on commit 66d5b39

Please sign in to comment.