From ca31715e4af8571ce7597223492bb7a01ce0f8a3 Mon Sep 17 00:00:00 2001 From: Chelsea Shaw Date: Tue, 18 Apr 2023 09:46:28 -0500 Subject: [PATCH 01/10] Add DOMPurify dependency --- ui/lib/core/package.json | 1 + ui/package.json | 1 + ui/yarn.lock | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/ui/lib/core/package.json b/ui/lib/core/package.json index b4326d2e24a1..3fcb0c734555 100644 --- a/ui/lib/core/package.json +++ b/ui/lib/core/package.json @@ -8,6 +8,7 @@ "date-fns": "*", "@icholy/duration": "*", "base64-js": "*", + "dompurify": "*", "ember-auto-import": "*", "ember-basic-dropdown": "*", "ember-cli-babel": "*", diff --git a/ui/package.json b/ui/package.json index e52812d44e35..ba7a1fdc79af 100644 --- a/ui/package.json +++ b/ui/package.json @@ -117,6 +117,7 @@ "date-fns-tz": "^1.2.2", "deepmerge": "^4.0.0", "doctoc": "^2.2.0", + "dompurify": "^3.0.2", "ember-auto-import": "2.4.2", "ember-basic-dropdown": "6.0.1", "ember-cli": "~4.4.0", diff --git a/ui/yarn.lock b/ui/yarn.lock index 8390944d2c93..4ef4ac95ccd4 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -8813,6 +8813,11 @@ domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3: dependencies: domelementtype "^2.3.0" +dompurify@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.0.2.tgz#bc4c7c011c825e7704341a285461d8d407d9429a" + integrity sha512-B8c6JdiEpxAKnd8Dm++QQxJL4lfuc757scZtcapj6qjTjrQzyq5iAyznLKVvK+77eYNiFblHBlt7MM0fOeqoKw== + domutils@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" From bd3009d52997a571ce13e581a3a4f597c29273c7 Mon Sep 17 00:00:00 2001 From: Chelsea Shaw Date: Tue, 18 Apr 2023 09:48:41 -0500 Subject: [PATCH 02/10] Add sanitized-html helper --- ui/lib/core/addon/helpers/sanitized-html.js | 13 +++++++ ui/lib/core/app/helpers/sanitized-html.js | 1 + .../helpers/sanitized-html-test.js | 35 +++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 ui/lib/core/addon/helpers/sanitized-html.js create mode 100644 ui/lib/core/app/helpers/sanitized-html.js create mode 100644 ui/tests/integration/helpers/sanitized-html-test.js diff --git a/ui/lib/core/addon/helpers/sanitized-html.js b/ui/lib/core/addon/helpers/sanitized-html.js new file mode 100644 index 000000000000..4c1fb079b0de --- /dev/null +++ b/ui/lib/core/addon/helpers/sanitized-html.js @@ -0,0 +1,13 @@ +import { helper } from '@ember/component/helper'; +import { debug } from '@ember/debug'; +import { htmlSafe } from '@ember/template'; +import { sanitize } from 'dompurify'; + +export default helper(function sanitizedHtml([htmlString]) { + try { + return htmlSafe(sanitize(htmlString)); + } catch (e) { + debug('Error sanitizing string', e); + return ''; + } +}); diff --git a/ui/lib/core/app/helpers/sanitized-html.js b/ui/lib/core/app/helpers/sanitized-html.js new file mode 100644 index 000000000000..7bd6cb8d9944 --- /dev/null +++ b/ui/lib/core/app/helpers/sanitized-html.js @@ -0,0 +1 @@ +export { default } from 'core/helpers/sanitized-html'; diff --git a/ui/tests/integration/helpers/sanitized-html-test.js b/ui/tests/integration/helpers/sanitized-html-test.js new file mode 100644 index 000000000000..80a279ac36e9 --- /dev/null +++ b/ui/tests/integration/helpers/sanitized-html-test.js @@ -0,0 +1,35 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'vault/tests/helpers'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Helper | sanitized-html', function (hooks) { + setupRenderingTest(hooks); + + test('it does not alter if string is safe', async function (assert) { + this.set('inputValue', 'height: 15.33px'); + + await render(hbs`{{sanitized-html this.inputValue}}`); + assert.dom(this.element).hasText('height: 15.33px'); + }); + + test('it strips unsafe HTML before rendering safe HTML', async function (assert) { + this.set( + 'inputValue', + '
This is something
' + ); + + await render(hbs`{{sanitized-html this.inputValue}}`); + assert.dom('[data-test-thing]').hasTagName('main'); + assert.dom('[data-test-thing]').hasText('This is something', 'preserves non-problematic content'); + assert.dom('[data-test-script]').doesNotExist('Script is stripped from render'); + }); + + test('it does not invoke functions passed as value', async function (assert) { + this.set('inputValue', () => { + window.alert('h4cK3d'); + }); + await render(hbs`{{sanitized-html this.inputValue}}`); + assert.dom(this.element).hasText("() => { window.alert('h4cK3d') }"); + }); +}); From 7a2b32d992c4dc033067f55072efd9f2ac5ffa26 Mon Sep 17 00:00:00 2001 From: Chelsea Shaw Date: Tue, 18 Apr 2023 09:49:15 -0500 Subject: [PATCH 03/10] Remove htmlSafe from diff-version-selector --- ui/app/components/diff-version-selector.js | 5 ++--- ui/app/templates/components/diff-version-selector.hbs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ui/app/components/diff-version-selector.js b/ui/app/components/diff-version-selector.js index 8daed6d3298c..dd0069fb7ebc 100644 --- a/ui/app/components/diff-version-selector.js +++ b/ui/app/components/diff-version-selector.js @@ -8,7 +8,6 @@ import Component from '@glimmer/component'; import { inject as service } from '@ember/service'; import { action } from '@ember/object'; import { tracked } from '@glimmer/tracking'; -import { htmlSafe } from '@ember/template'; /** * @module DiffVersionSelector @@ -64,10 +63,10 @@ export default class DiffVersionSelector extends Component { if (delta === undefined) { this.statesMatch = true; // params: value, replacer (all properties included), space (white space and indentation, line break, etc.) - this.visualDiff = htmlSafe(JSON.stringify(leftSideVersionData, undefined, 2)); + this.visualDiff = JSON.stringify(leftSideVersionData, undefined, 2); } else { this.statesMatch = false; - this.visualDiff = htmlSafe(jsondiffpatch.formatters.html.format(delta, rightSideVersionData)); + this.visualDiff = jsondiffpatch.formatters.html.format(delta, rightSideVersionData); } } diff --git a/ui/app/templates/components/diff-version-selector.hbs b/ui/app/templates/components/diff-version-selector.hbs index 6ac766ff806e..9114f3886755 100644 --- a/ui/app/templates/components/diff-version-selector.hbs +++ b/ui/app/templates/components/diff-version-selector.hbs @@ -98,5 +98,5 @@
-
{{this.visualDiff}}
+
{{sanitized-html this.visualDiff}}
\ No newline at end of file From 99aa5690af37d5c18df5e5ed1434e375208bdead Mon Sep 17 00:00:00 2001 From: Chelsea Shaw Date: Tue, 18 Apr 2023 09:49:56 -0500 Subject: [PATCH 04/10] Remove htmlSafe from replication-dashboard --- ui/lib/core/addon/components/replication-dashboard.js | 7 ++----- .../addon/templates/components/replication-dashboard.hbs | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ui/lib/core/addon/components/replication-dashboard.js b/ui/lib/core/addon/components/replication-dashboard.js index ff9e5e8d3c05..1993c6d57826 100644 --- a/ui/lib/core/addon/components/replication-dashboard.js +++ b/ui/lib/core/addon/components/replication-dashboard.js @@ -7,7 +7,6 @@ import Component from '@ember/component'; import { computed } from '@ember/object'; import { clusterStates } from 'core/helpers/cluster-states'; import { capitalize } from '@ember/string'; -import { htmlSafe } from '@ember/template'; import layout from '../templates/components/replication-dashboard'; /** @@ -35,7 +34,7 @@ import layout from '../templates/components/replication-dashboard'; * @param {Boolean} [isSummaryDashboard=false] - Only true when the cluster is both a dr and performance primary. If true, replicationDetailsSummary is populated and used to pass through the cluster details. * @param {Object} replicationDetailsSummary=null - An Ember data object computed off the Ember Model. It combines the Model.dr and Model.performance objects into one and contains details specific to the mode replication. * @param {Object} replicationDetails=null - An Ember data object pulled from the Ember Model. It contains details specific to the whether the replication is dr or performance. - * @param {String} clusterMode=null - The cluster mode passed through to a table component. + * @param {String} clusterMode=null - The cluster mode passed through to a table component. * @param {Object} reindexingDetails=null - An Ember data object used to show a reindexing progress bar. */ @@ -94,9 +93,7 @@ export default Component.extend({ }), reindexMessage: computed('isSecondary', 'progressBar', function () { if (!this.isSecondary) { - return htmlSafe( - 'This can cause a delay depending on the size of the data store. You can not use Vault during this time.' - ); + return 'This can cause a delay depending on the size of the data store. You can not use Vault during this time.'; } return 'This can cause a delay depending on the size of the data store. You can use Vault during this time.'; }), diff --git a/ui/lib/core/addon/templates/components/replication-dashboard.hbs b/ui/lib/core/addon/templates/components/replication-dashboard.hbs index 834619b093e7..8e0aaef58eb4 100644 --- a/ui/lib/core/addon/templates/components/replication-dashboard.hbs +++ b/ui/lib/core/addon/templates/components/replication-dashboard.hbs @@ -5,7 +5,7 @@ @title={{concat "Re-indexing in progress" this.reindexingStage}} @type="info" @progressBar={{this.progressBar}} - @message={{this.reindexMessage}} + @message={{sanitized-html this.reindexMessage}} data-test-isReindexing /> From ce738242f39c17ee66fa22ced5b4cd99c4ff26f5 Mon Sep 17 00:00:00 2001 From: Chelsea Shaw Date: Tue, 18 Apr 2023 09:50:33 -0500 Subject: [PATCH 05/10] Remove htmlSafe from k8s role form --- .../kubernetes/addon/components/page/role/create-and-edit.hbs | 2 +- .../kubernetes/addon/components/page/role/create-and-edit.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ui/lib/kubernetes/addon/components/page/role/create-and-edit.hbs b/ui/lib/kubernetes/addon/components/page/role/create-and-edit.hbs index ac2780d6b812..fad90586b9d7 100644 --- a/ui/lib/kubernetes/addon/components/page/role/create-and-edit.hbs +++ b/ui/lib/kubernetes/addon/components/page/role/create-and-edit.hbs @@ -109,7 +109,7 @@ @value={{template.rules}} @mode="ruby" @valueUpdated={{fn (mut template.rules)}} - @helpText={{this.roleRulesHelpText}} + @helpText={{sanitized-html this.roleRulesHelpText}} >