diff --git a/cypress/e2e/secure-option-values.cy.ts b/cypress/e2e/secure-option-values.cy.ts new file mode 100644 index 0000000..f1ed9ab --- /dev/null +++ b/cypress/e2e/secure-option-values.cy.ts @@ -0,0 +1,58 @@ +describe('Secure option values', () => { + const existingValueMountId = 'vs-secure-existing-value'; + const newValueMountId = 'vs-secure-new-value'; + + it('preserves the original value in the hidden form input', () => { + cy.visit('get-started'); + + cy.window().then((win) => { + const $ele = win.document.createElement('div'); + $ele.id = existingValueMountId; + win.document.body.appendChild($ele); + + // @ts-expect-error - VirtualSelect is attached to window by the bundle + win.VirtualSelect.init({ + ele: $ele, + enableSecureText: true, + multiple: true, + setValueAsArray: true, + options: [{ value: '<', label: 'Value with unsafe char <' }], + }); + }); + + cy.get(`#${existingValueMountId}`).find('.vscomp-toggle-button').click(); + cy.get(`#${existingValueMountId}`).find('.vscomp-option').click(); + + cy.get(`#${existingValueMountId}`).find('.vscomp-hidden-input').should('have.value', '["<"]'); + cy.get(`#${existingValueMountId}`).find('.vscomp-option-text').should('contain.text', 'Value with unsafe char <'); + }); + + it('preserves new values without inserting their markup', () => { + const payload = '">'; + + cy.visit('get-started'); + + cy.window().then((win) => { + const $ele = win.document.createElement('div'); + $ele.id = newValueMountId; + win.document.body.appendChild($ele); + + // @ts-expect-error - VirtualSelect is attached to window by the bundle + win.VirtualSelect.init({ + ele: $ele, + allowNewOption: true, + enableSecureText: true, + multiple: true, + setValueAsArray: true, + options: [], + }); + + // @ts-expect-error - setValue is attached to the initialized element + $ele.setValue([payload]); + }); + + cy.get(`#${newValueMountId}`).find('.vscomp-hidden-input').should('have.value', JSON.stringify([payload])); + cy.get(`#${newValueMountId}`).find('img').should('not.exist'); + cy.window().its('__vsValueXss').should('be.undefined'); + }); +}); diff --git a/dist/virtual-select.js b/dist/virtual-select.js index 42bceea..6120d8b 100644 --- a/dist/virtual-select.js +++ b/dist/virtual-select.js @@ -965,7 +965,7 @@ class VirtualSelect { } } html += `
${leftSection} @@ -1981,7 +1981,7 @@ class VirtualSelect { [labelKey]: d }; } - const value = secureText(getString(d[valueKey])); + const value = getString(d[valueKey]); const label = secureText(getString(d[labelKey])); const childOptions = d.options; const isGroupTitle = !!childOptions; @@ -2468,7 +2468,7 @@ class VirtualSelect { const newOption = this.getNewOption(); if (newOption) { const newIndex = newOption.index; - this.setOptionProp(newIndex, 'value', this.secureText(value)); + this.setOptionProp(newIndex, 'value', value); this.setOptionProp(newIndex, 'label', this.secureText(value)); } else { const data = { @@ -2697,7 +2697,7 @@ class VirtualSelect { getString } = Utils; const secureText = this.secureText.bind(this); - const value = secureText(getString(data.value)); + const value = getString(data.value); const label = secureText(getString(data.label)); const description = secureText(getString(data.description)); return { diff --git a/docs/assets/virtual-select.js b/docs/assets/virtual-select.js index 42bceea..6120d8b 100644 --- a/docs/assets/virtual-select.js +++ b/docs/assets/virtual-select.js @@ -965,7 +965,7 @@ class VirtualSelect { } } html += `
${leftSection} @@ -1981,7 +1981,7 @@ class VirtualSelect { [labelKey]: d }; } - const value = secureText(getString(d[valueKey])); + const value = getString(d[valueKey]); const label = secureText(getString(d[labelKey])); const childOptions = d.options; const isGroupTitle = !!childOptions; @@ -2468,7 +2468,7 @@ class VirtualSelect { const newOption = this.getNewOption(); if (newOption) { const newIndex = newOption.index; - this.setOptionProp(newIndex, 'value', this.secureText(value)); + this.setOptionProp(newIndex, 'value', value); this.setOptionProp(newIndex, 'label', this.secureText(value)); } else { const data = { @@ -2697,7 +2697,7 @@ class VirtualSelect { getString } = Utils; const secureText = this.secureText.bind(this); - const value = secureText(getString(data.value)); + const value = getString(data.value); const label = secureText(getString(data.label)); const description = secureText(getString(data.description)); return { diff --git a/src/virtual-select.js b/src/virtual-select.js index 523cbd4..461f9d3 100644 --- a/src/virtual-select.js +++ b/src/virtual-select.js @@ -421,7 +421,7 @@ export class VirtualSelect { } html += `
${leftSection} @@ -1559,7 +1559,7 @@ export class VirtualSelect { d = { [valueKey]: d, [labelKey]: d }; } - const value = secureText(getString(d[valueKey])); + const value = getString(d[valueKey]); const label = secureText(getString(d[labelKey])); const childOptions = d.options; const isGroupTitle = !!childOptions; @@ -2128,7 +2128,7 @@ export class VirtualSelect { if (newOption) { const newIndex = newOption.index; - this.setOptionProp(newIndex, 'value', this.secureText(value)); + this.setOptionProp(newIndex, 'value', value); this.setOptionProp(newIndex, 'label', this.secureText(value)); } else { const data = { @@ -2384,7 +2384,7 @@ export class VirtualSelect { const { getString } = Utils; const secureText = this.secureText.bind(this); - const value = secureText(getString(data.value)); + const value = getString(data.value); const label = secureText(getString(data.label)); const description = secureText(getString(data.description));