From 4104dd314065568c7da6b74bd4edc3f9fc9249ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20D=C4=99bi=C5=84ski?= Date: Fri, 15 Mar 2024 15:24:54 +0100 Subject: [PATCH 1/4] IBX-7442: Escaped values in JS --- .../public/js/scripts/core/dropdown.js | 27 +++++++++++-------- .../public/js/scripts/helpers/text.helper.js | 14 ++++++++++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/bundle/Resources/public/js/scripts/core/dropdown.js b/src/bundle/Resources/public/js/scripts/core/dropdown.js index 1818361439..6ee6b8b077 100644 --- a/src/bundle/Resources/public/js/scripts/core/dropdown.js +++ b/src/bundle/Resources/public/js/scripts/core/dropdown.js @@ -87,7 +87,9 @@ createSelectedItem(value, label, icon) { const container = doc.createElement('div'); - const selectedItemRendered = this.selectedItemTemplate.replace('{{ value }}', value).replace('{{ label }}', label); + const selectedItemRendered = this.selectedItemTemplate + .replace('{{ value }}', ibexa.helpers.text.escapeDataset(value)) + .replace('{{ label }}', label); container.insertAdjacentHTML('beforeend', selectedItemRendered); @@ -149,13 +151,14 @@ } selectOption(value) { - const optionToSelect = this.itemsListContainer.querySelector(`.ibexa-dropdown__item[data-value="${value}"`); + const optionToSelect = this.itemsListContainer.querySelector(`.ibexa-dropdown__item[data-value=${JSON.stringify(value)}]`); return this.onSelect(optionToSelect, true); } onSelect(element, selected) { - const { value, choiceIcon } = element.dataset; + const { choiceIcon } = element.dataset; + const value = JSON.stringify(element.dataset.value); if (this.canSelectOnlyOne && selected) { this.hideOptions(); @@ -163,14 +166,14 @@ } if (value) { - this.sourceInput.querySelector(`[value="${value}"]`).selected = selected; + this.sourceInput.querySelector(`[value=${value}]`).selected = selected; if (!this.canSelectOnlyOne) { element.querySelector('.ibexa-input').checked = selected; } } - this.itemsListContainer.querySelector(`[data-value="${value}"]`).classList.toggle('ibexa-dropdown__item--selected', selected); + this.itemsListContainer.querySelector(`[data-value=${value}]`).classList.toggle('ibexa-dropdown__item--selected', selected); const selectedItemsList = this.container.querySelector('.ibexa-dropdown__selection-info'); @@ -181,7 +184,7 @@ this.selectedItemsContainer.insertBefore(this.createSelectedItem(value, label, choiceIcon), targetPlace); } else { - const valueNode = selectedItemsList.querySelector(`[data-value="${value}"]`); + const valueNode = selectedItemsList.querySelector(`[data-value=${value}]`); if (valueNode) { valueNode.remove(); @@ -235,9 +238,9 @@ } deselectOption(option) { - const { value } = option.dataset; - const optionSelect = this.sourceInput.querySelector(`[value="${value}"]`); - const itemSelected = this.itemsListContainer.querySelector(`[data-value="${value}"]`); + const value = JSON.stringify(option.dataset.value); + const optionSelect = this.sourceInput.querySelector(`[value=${value}]`); + const itemSelected = this.itemsListContainer.querySelector(`[data-value=${value}]`); itemSelected.classList.remove('ibexa-dropdown__item--selected'); @@ -383,14 +386,16 @@ } removeOption(value) { - const optionNode = this.itemsListContainer.querySelector(`[data-value="${value}"]`); + const optionNode = this.itemsListContainer.querySelector(`[data-value=${JSON.stringify(value)}]`); optionNode.remove(); } createOption(value, label) { const container = doc.createElement('div'); - const itemRendered = this.itemTemplate.replaceAll('{{ value }}', value).replaceAll('{{ label }}', label); + const itemRendered = this.itemTemplate + .replaceAll('{{ value }}', ibexa.helpers.text.escapeDataset(value)) + .replaceAll('{{ label }}', label); container.insertAdjacentHTML('beforeend', itemRendered); diff --git a/src/bundle/Resources/public/js/scripts/helpers/text.helper.js b/src/bundle/Resources/public/js/scripts/helpers/text.helper.js index 4a42f9b113..9d96878667 100644 --- a/src/bundle/Resources/public/js/scripts/helpers/text.helper.js +++ b/src/bundle/Resources/public/js/scripts/helpers/text.helper.js @@ -7,7 +7,21 @@ return stringTempNode.innerHTML; }; + const escapeDataset = (str) => { + if (str === null) { + return ''; + } + + return String(str) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + }; + ibexa.addConfig('helpers.text', { escapeHTML, + escapeDataset, }); })(window, window.document, window.ibexa); From ec0fdb310c27c520a367e69452cc159376ded11b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20D=C4=99bi=C5=84ski?= Date: Mon, 18 Mar 2024 10:41:11 +0100 Subject: [PATCH 2/4] Added cast to String --- .../Resources/public/js/scripts/core/dropdown.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/bundle/Resources/public/js/scripts/core/dropdown.js b/src/bundle/Resources/public/js/scripts/core/dropdown.js index 6ee6b8b077..684b337381 100644 --- a/src/bundle/Resources/public/js/scripts/core/dropdown.js +++ b/src/bundle/Resources/public/js/scripts/core/dropdown.js @@ -151,14 +151,15 @@ } selectOption(value) { - const optionToSelect = this.itemsListContainer.querySelector(`.ibexa-dropdown__item[data-value=${JSON.stringify(value)}]`); + const clearValue = JSON.stringify(String(value)); + const optionToSelect = this.itemsListContainer.querySelector(`.ibexa-dropdown__item[data-value=${clearValue}]`); return this.onSelect(optionToSelect, true); } onSelect(element, selected) { const { choiceIcon } = element.dataset; - const value = JSON.stringify(element.dataset.value); + const value = JSON.stringify(String(element.dataset.value)); if (this.canSelectOnlyOne && selected) { this.hideOptions(); @@ -238,7 +239,7 @@ } deselectOption(option) { - const value = JSON.stringify(option.dataset.value); + const value = JSON.stringify(String(option.dataset.value)); const optionSelect = this.sourceInput.querySelector(`[value=${value}]`); const itemSelected = this.itemsListContainer.querySelector(`[data-value=${value}]`); @@ -386,7 +387,8 @@ } removeOption(value) { - const optionNode = this.itemsListContainer.querySelector(`[data-value=${JSON.stringify(value)}]`); + const clearValue = JSON.stringify(String(value)); + const optionNode = this.itemsListContainer.querySelector(`[data-value=${clearValue}]`); optionNode.remove(); } From b73d5ca9fc73cb51f127ea4771af36d838e40778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20D=C4=99bi=C5=84ski?= Date: Tue, 19 Mar 2024 12:49:14 +0100 Subject: [PATCH 3/4] Changed function name --- src/bundle/Resources/public/js/scripts/core/dropdown.js | 4 ++-- src/bundle/Resources/public/js/scripts/helpers/text.helper.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bundle/Resources/public/js/scripts/core/dropdown.js b/src/bundle/Resources/public/js/scripts/core/dropdown.js index 684b337381..74835d74dd 100644 --- a/src/bundle/Resources/public/js/scripts/core/dropdown.js +++ b/src/bundle/Resources/public/js/scripts/core/dropdown.js @@ -88,7 +88,7 @@ createSelectedItem(value, label, icon) { const container = doc.createElement('div'); const selectedItemRendered = this.selectedItemTemplate - .replace('{{ value }}', ibexa.helpers.text.escapeDataset(value)) + .replace('{{ value }}', ibexa.helpers.text.escapeHTMLAttribute(value)) .replace('{{ label }}', label); container.insertAdjacentHTML('beforeend', selectedItemRendered); @@ -396,7 +396,7 @@ createOption(value, label) { const container = doc.createElement('div'); const itemRendered = this.itemTemplate - .replaceAll('{{ value }}', ibexa.helpers.text.escapeDataset(value)) + .replaceAll('{{ value }}', ibexa.helpers.text.escapeHTMLAttribute(value)) .replaceAll('{{ label }}', label); container.insertAdjacentHTML('beforeend', itemRendered); diff --git a/src/bundle/Resources/public/js/scripts/helpers/text.helper.js b/src/bundle/Resources/public/js/scripts/helpers/text.helper.js index 9d96878667..b86c7e9250 100644 --- a/src/bundle/Resources/public/js/scripts/helpers/text.helper.js +++ b/src/bundle/Resources/public/js/scripts/helpers/text.helper.js @@ -7,7 +7,7 @@ return stringTempNode.innerHTML; }; - const escapeDataset = (str) => { + const escapeHTMLAttribute = (str) => { if (str === null) { return ''; } @@ -22,6 +22,6 @@ ibexa.addConfig('helpers.text', { escapeHTML, - escapeDataset, + escapeHTMLAttribute, }); })(window, window.document, window.ibexa); From 16589e6960f3edbb9ef96fb9c89e67bed98c27cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20D=C4=99bi=C5=84ski?= Date: Tue, 19 Mar 2024 12:50:44 +0100 Subject: [PATCH 4/4] corrected variable --- src/bundle/Resources/public/js/scripts/core/dropdown.js | 8 ++++---- .../Resources/public/js/scripts/helpers/text.helper.js | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bundle/Resources/public/js/scripts/core/dropdown.js b/src/bundle/Resources/public/js/scripts/core/dropdown.js index 74835d74dd..30a12c6446 100644 --- a/src/bundle/Resources/public/js/scripts/core/dropdown.js +++ b/src/bundle/Resources/public/js/scripts/core/dropdown.js @@ -151,8 +151,8 @@ } selectOption(value) { - const clearValue = JSON.stringify(String(value)); - const optionToSelect = this.itemsListContainer.querySelector(`.ibexa-dropdown__item[data-value=${clearValue}]`); + const stringifiedValue = JSON.stringify(String(value)); + const optionToSelect = this.itemsListContainer.querySelector(`.ibexa-dropdown__item[data-value=${stringifiedValue}]`); return this.onSelect(optionToSelect, true); } @@ -387,8 +387,8 @@ } removeOption(value) { - const clearValue = JSON.stringify(String(value)); - const optionNode = this.itemsListContainer.querySelector(`[data-value=${clearValue}]`); + const stringifiedValue = JSON.stringify(String(value)); + const optionNode = this.itemsListContainer.querySelector(`[data-value=${stringifiedValue}]`); optionNode.remove(); } diff --git a/src/bundle/Resources/public/js/scripts/helpers/text.helper.js b/src/bundle/Resources/public/js/scripts/helpers/text.helper.js index b86c7e9250..3fee9c5fc0 100644 --- a/src/bundle/Resources/public/js/scripts/helpers/text.helper.js +++ b/src/bundle/Resources/public/js/scripts/helpers/text.helper.js @@ -7,12 +7,12 @@ return stringTempNode.innerHTML; }; - const escapeHTMLAttribute = (str) => { - if (str === null) { + const escapeHTMLAttribute = (string) => { + if (string === null) { return ''; } - return String(str) + return String(string) .replace(/&/g, '&') .replace(//g, '>')