From 2a9d72133d52af1ca72944f1d19474957b54d618 Mon Sep 17 00:00:00 2001 From: Florian Vick Date: Wed, 3 Feb 2021 20:58:54 +0100 Subject: [PATCH] Prevent `getSelector` from returning URLs as selector (#32586) * added checks to getSelector in util to prevent returning hrefs that are invalid selectors * restored compatibility for the class selector and added test cases for keeping urls from being returned as a selector Co-authored-by: XhmikosR --- js/src/util/index.js | 15 ++++++++++++++- js/tests/unit/util/index.spec.js | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/js/src/util/index.js b/js/src/util/index.js index 22d0a578b8..bd519cce07 100644 --- a/js/src/util/index.js +++ b/js/src/util/index.js @@ -36,7 +36,20 @@ const getSelector = element => { let selector = element.getAttribute('data-bs-target') if (!selector || selector === '#') { - const hrefAttr = element.getAttribute('href') + let hrefAttr = element.getAttribute('href') + + // The only valid content that could double as a selector are IDs or classes, + // so everything starting with `#` or `.`. If a "real" URL is used as the selector, + // `document.querySelector` will rightfully complain it is invalid. + // See https://github.com/twbs/bootstrap/issues/32273 + if (!hrefAttr || (!hrefAttr.includes('#') && !hrefAttr.startsWith('.'))) { + return null + } + + // Just in case some CMS puts out a full URL with the anchor appended + if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) { + hrefAttr = '#' + hrefAttr.split('#')[1] + } selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null } diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js index 00ab44f1eb..935e021dd7 100644 --- a/js/tests/unit/util/index.spec.js +++ b/js/tests/unit/util/index.spec.js @@ -57,6 +57,28 @@ describe('Util', () => { expect(Util.getSelectorFromElement(testEl)).toEqual('.target') }) + it('should return null if a selector from a href is a url without an anchor', () => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(Util.getSelectorFromElement(testEl)).toBeNull() + }) + + it('should return the anchor if a selector from a href is a url', () => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(Util.getSelectorFromElement(testEl)).toEqual('#target') + }) + it('should return null if selector not found', () => { fixtureEl.innerHTML = ''