diff --git a/changelog/20235.txt b/changelog/20235.txt
new file mode 100644
index 000000000..d1b9f8a6e
--- /dev/null
+++ b/changelog/20235.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+ui: remove use of htmlSafe except when first sanitized
+```
diff --git a/ui/app/components/diff-version-selector.js b/ui/app/components/diff-version-selector.js
index 8daed6d32..dd0069fb7 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/components/wizard-content.js b/ui/app/components/wizard-content.js
index 40615ed05..8cee2e9bf 100644
--- a/ui/app/components/wizard-content.js
+++ b/ui/app/components/wizard-content.js
@@ -8,7 +8,6 @@ import { inject as service } from '@ember/service';
import Component from '@ember/component';
import { computed } from '@ember/object';
import { FEATURE_MACHINE_STEPS, INIT_STEPS } from 'vault/helpers/wizard-constants';
-import { htmlSafe } from '@ember/template';
export default Component.extend({
wizard: service(),
@@ -89,25 +88,25 @@ export default Component.extend({
const bar = [];
if (this.currentTutorialProgress) {
bar.push({
- style: htmlSafe(`width:${this.currentTutorialProgress.percentage}%;`),
+ style: `width:${this.currentTutorialProgress.percentage}%;`,
completed: false,
showIcon: true,
});
} else {
if (this.currentFeatureProgress) {
this.completedFeatures.forEach((feature) => {
- bar.push({ style: htmlSafe('width:100%;'), completed: true, feature: feature, showIcon: true });
+ bar.push({ style: 'width:100%;', completed: true, feature: feature, showIcon: true });
});
this.wizard.featureList.forEach((feature) => {
if (feature === this.currentMachine) {
bar.push({
- style: htmlSafe(`width:${this.currentFeatureProgress.percentage}%;`),
+ style: `width:${this.currentFeatureProgress.percentage}%;`,
completed: this.currentFeatureProgress.percentage == 100 ? true : false,
feature: feature,
showIcon: true,
});
} else {
- bar.push({ style: htmlSafe('width:0%;'), completed: false, feature: feature, showIcon: true });
+ bar.push({ style: 'width:0%;', completed: false, feature: feature, showIcon: true });
}
});
}
diff --git a/ui/app/components/wizard/features-selection.js b/ui/app/components/wizard/features-selection.js
index 944b1d9c7..a14e99318 100644
--- a/ui/app/components/wizard/features-selection.js
+++ b/ui/app/components/wizard/features-selection.js
@@ -8,7 +8,6 @@ import { inject as service } from '@ember/service';
import Component from '@ember/component';
import { computed } from '@ember/object';
import { FEATURE_MACHINE_TIME } from 'vault/helpers/wizard-constants';
-import { htmlSafe } from '@ember/template';
export default Component.extend({
wizard: service(),
@@ -55,10 +54,10 @@ export default Component.extend({
}),
selectProgress: computed('selectedFeatures', function () {
let bar = this.selectedFeatures.map((feature) => {
- return { style: htmlSafe('width:0%;'), completed: false, showIcon: true, feature: feature };
+ return { style: 'width:0%;', completed: false, showIcon: true, feature: feature };
});
if (bar.length === 0) {
- bar = [{ style: htmlSafe('width:0%;'), showIcon: false }];
+ bar = [{ style: 'width:0%;', showIcon: false }];
}
return bar;
}),
diff --git a/ui/app/templates/components/diff-version-selector.hbs b/ui/app/templates/components/diff-version-selector.hbs
index 6ac766ff8..9114f3886 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
diff --git a/ui/app/templates/components/wizard-progress.hbs b/ui/app/templates/components/wizard-progress.hbs
index 6bae1819f..29899c5db 100644
--- a/ui/app/templates/components/wizard-progress.hbs
+++ b/ui/app/templates/components/wizard-progress.hbs
@@ -2,7 +2,7 @@
{{#each @progressBar as |bar|}}
-
+
{{#if bar.showIcon}}
diff --git a/ui/lib/core/addon/components/confirm.js b/ui/lib/core/addon/components/confirm.js
index a287b78af..f7511ce42 100644
--- a/ui/lib/core/addon/components/confirm.js
+++ b/ui/lib/core/addon/components/confirm.js
@@ -5,7 +5,6 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
-import { htmlSafe } from '@ember/template';
import layout from '../templates/components/confirm';
import { next } from '@ember/runloop';
@@ -34,7 +33,7 @@ export default Component.extend({
height: 0,
focusTrigger: null,
style: computed('height', function () {
- return htmlSafe(`height: ${this.height}px`);
+ return `height: ${this.height}px`;
}),
wormholeReference: null,
wormholeId: computed('elementId', function () {
diff --git a/ui/lib/core/addon/components/replication-dashboard.js b/ui/lib/core/addon/components/replication-dashboard.js
index ff9e5e8d3..1993c6d57 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/helpers/sanitized-html.js b/ui/lib/core/addon/helpers/sanitized-html.js
new file mode 100644
index 000000000..cfa99d723
--- /dev/null
+++ b/ui/lib/core/addon/helpers/sanitized-html.js
@@ -0,0 +1,14 @@
+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);
+ // I couldn't get this to actually fail but as a fallback render the value as-is
+ return htmlString;
+ }
+});
diff --git a/ui/lib/core/addon/templates/components/replication-dashboard.hbs b/ui/lib/core/addon/templates/components/replication-dashboard.hbs
index 834619b09..8e0aaef58 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
/>