From 62f7600aa403b527589432059a2142a05aa5d2e5 Mon Sep 17 00:00:00 2001 From: Jono M Date: Thu, 11 May 2023 09:53:05 +1200 Subject: [PATCH] Update search text highlighting to escape HTML (#16760) refs: https://github.com/TryGhost/Team/issues/2390 Escapes each matched and non-matched segment of the post title in the admin search field, to make sure they're displayed in plain text but still have matches highlighted. --- ghost/admin/app/helpers/highlighted-text.js | 19 ++++++++++++++++++- .../unit/helpers/highlighted-text-test.js | 6 ++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/ghost/admin/app/helpers/highlighted-text.js b/ghost/admin/app/helpers/highlighted-text.js index cb6d3c40aa..f2512cc57f 100644 --- a/ghost/admin/app/helpers/highlighted-text.js +++ b/ghost/admin/app/helpers/highlighted-text.js @@ -1,11 +1,28 @@ +import Ember from 'ember'; import {helper} from '@ember/component/helper'; import {htmlSafe} from '@ember/template'; +const {Handlebars} = Ember; + export function highlightedText([text, termToHighlight]) { // replace any non-word character with an escaped character let sanitisedTerm = termToHighlight.replace(new RegExp(/\W/ig), '\\$&'); + let termMatcher = new RegExp(sanitisedTerm, 'ig'); - return htmlSafe(text.replace(new RegExp(sanitisedTerm, 'ig'), '$&')); + let matches = text.match(termMatcher) || []; + let nonMatches = text.split(termMatcher); + + let htmlSafeResult = ''; + + nonMatches.forEach((nonMatch, index) => { + htmlSafeResult += Handlebars.Utils.escapeExpression(nonMatch); + + if (matches[index]) { + htmlSafeResult += `${Handlebars.Utils.escapeExpression(matches[index])}`; + } + }); + + return htmlSafe(htmlSafeResult); } export default helper(highlightedText); diff --git a/ghost/admin/tests/unit/helpers/highlighted-text-test.js b/ghost/admin/tests/unit/helpers/highlighted-text-test.js index 3ec4b69088..6130219fe2 100644 --- a/ghost/admin/tests/unit/helpers/highlighted-text-test.js +++ b/ghost/admin/tests/unit/helpers/highlighted-text-test.js @@ -13,4 +13,10 @@ describe('Unit: Helper: highlighted-text', function () { expect(result).to.be.an('object'); expect(result.string).to.equal('Test'); }); + + it('escapes html', function () { + let result = highlightedText(['', 'oops']); + expect(result).to.be.an('object'); + expect(result.string).to.equal('<script>alert("oops")</script>'); + }); });