]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Prevent `getSelector` from returning URLs as selector (#32586)
authorFlorian Vick <florian@eagle-eye-studios.net>
Wed, 3 Feb 2021 19:58:54 +0000 (20:58 +0100)
committerGitHub <noreply@github.com>
Wed, 3 Feb 2021 19:58:54 +0000 (21:58 +0200)
* 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 <xhmikosr@gmail.com>
js/src/util/index.js
js/tests/unit/util/index.spec.js

index 22d0a578b81e7a6da8ec558d34ba17f1993441a5..bd519cce07b64ab678818e0dd9a68d59ee4a59de 100644 (file)
@@ -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
   }
index 00ab44f1ebe7454566d5b0f7f4794e933dce0cc1..935e021dd7db6d38b5e384cd7c146d34a035bd03 100644 (file)
@@ -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 = [
+        '<a id="test" data-bs-target="#" href="foo/bar.html"></a>',
+        '<div class="target"></div>'
+      ].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 = [
+        '<a id="test" data-bs-target="#" href="foo/bar.html#target"></a>',
+        '<div id="target"></div>'
+      ].join('')
+
+      const testEl = fixtureEl.querySelector('#test')
+
+      expect(Util.getSelectorFromElement(testEl)).toEqual('#target')
+    })
+
     it('should return null if selector not found', () => {
       fixtureEl.innerHTML = '<a id="test" href=".target"></a>'