Skip to content

Commit a689120

Browse files
committed
throw error when folks try to use a bad selector
1 parent 9efed82 commit a689120

File tree

5 files changed

+45
-55
lines changed

5 files changed

+45
-55
lines changed

js/src/util.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,11 @@ const Util = (($) => {
7979
let selector = element.getAttribute('data-target')
8080

8181
if (!selector || selector === '#') {
82-
selector = (element.getAttribute('href') || '').trim()
82+
const hrefAttr = element.getAttribute('href')
83+
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : ''
8384
}
8485

85-
try {
86-
return document.querySelector(selector) ? selector : null
87-
} catch (err) {
88-
return null
89-
}
86+
return selector && document.querySelector(selector) ? selector : null
9087
},
9188

9289
getTransitionDurationFromElement(element) {

js/tests/unit/dropdown.js

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -216,30 +216,6 @@ $(function () {
216216
$dropdown.trigger('click')
217217
})
218218

219-
QUnit.test('should test if element has a # before assuming it\'s a selector', function (assert) {
220-
assert.expect(1)
221-
var done = assert.async()
222-
var dropdownHTML = '<div class="tabs">' +
223-
'<div class="dropdown">' +
224-
'<a href="/foo/" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>' +
225-
'<div class="dropdown-menu">' +
226-
'<a class="dropdown-item" href="#">Secondary link</a>' +
227-
'<a class="dropdown-item" href="#">Something else here</a>' +
228-
'<div class="divider"/>' +
229-
'<a class="dropdown-item" href="#">Another link</a>' +
230-
'</div>' +
231-
'</div>' +
232-
'</div>'
233-
var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown()
234-
$dropdown
235-
.parent('.dropdown')
236-
.on('shown.bs.dropdown', function () {
237-
assert.ok($dropdown.parent('.dropdown').hasClass('show'), '"show" class added on click')
238-
done()
239-
})
240-
$dropdown.trigger('click')
241-
})
242-
243219
QUnit.test('should remove "show" class if body is clicked', function (assert) {
244220
assert.expect(2)
245221
var done = assert.async()

js/tests/unit/modal.js

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -607,36 +607,40 @@ $(function () {
607607
assert.expect(1)
608608
var done = assert.async()
609609

610-
var $toggleBtn = $('<button data-toggle="modal" data-target="&lt;div id=&quot;modal-test&quot;&gt;&lt;div class=&quot;contents&quot;&lt;div&lt;div id=&quot;close&quot; data-dismiss=&quot;modal&quot;/&gt;&lt;/div&gt;&lt;/div&gt;"/>')
611-
.appendTo('#qunit-fixture')
610+
try {
611+
var $toggleBtn = $('<button data-toggle="modal" data-target="&lt;div id=&quot;modal-test&quot;&gt;&lt;div class=&quot;contents&quot;&lt;div&lt;div id=&quot;close&quot; data-dismiss=&quot;modal&quot;/&gt;&lt;/div&gt;&lt;/div&gt;"/>')
612+
.appendTo('#qunit-fixture')
612613

613-
$toggleBtn.trigger('click')
614-
setTimeout(function () {
614+
$toggleBtn.trigger('click')
615+
} catch (e) {
615616
assert.strictEqual($('#modal-test').length, 0, 'target has not been parsed and added to the document')
616617
done()
617-
}, 1)
618+
}
618619
})
619620

620621
QUnit.test('should not execute js from target', function (assert) {
621622
assert.expect(0)
622623
var done = assert.async()
623624

624-
// This toggle button contains XSS payload in its data-target
625-
// Note: it uses the onerror handler of an img element to execute the js, because a simple script element does not work here
626-
// a script element works in manual tests though, so here it is likely blocked by the qunit framework
627-
var $toggleBtn = $('<button data-toggle="modal" data-target="&lt;div&gt;&lt;image src=&quot;missing.png&quot; onerror=&quot;$(&apos;#qunit-fixture button.control&apos;).trigger(&apos;click&apos;)&quot;&gt;&lt;/div&gt;"/>')
628-
.appendTo('#qunit-fixture')
629-
// The XSS payload above does not have a closure over this function and cannot access the assert object directly
630-
// However, it can send a click event to the following control button, which will then fail the assert
631-
$('<button>')
632-
.addClass('control')
633-
.on('click', function () {
634-
assert.notOk(true, 'XSS payload is not executed as js')
635-
})
636-
.appendTo('#qunit-fixture')
637-
638-
$toggleBtn.trigger('click')
639-
setTimeout(done, 500)
625+
try {
626+
// This toggle button contains XSS payload in its data-target
627+
// Note: it uses the onerror handler of an img element to execute the js, because a simple script element does not work here
628+
// a script element works in manual tests though, so here it is likely blocked by the qunit framework
629+
var $toggleBtn = $('<button data-toggle="modal" data-target="&lt;div&gt;&lt;image src=&quot;missing.png&quot; onerror=&quot;$(&apos;#qunit-fixture button.control&apos;).trigger(&apos;click&apos;)&quot;&gt;&lt;/div&gt;"/>')
630+
.appendTo('#qunit-fixture')
631+
// The XSS payload above does not have a closure over this function and cannot access the assert object directly
632+
// However, it can send a click event to the following control button, which will then fail the assert
633+
$('<button>')
634+
.addClass('control')
635+
.on('click', function () {
636+
assert.notOk(true, 'XSS payload is not executed as js')
637+
})
638+
.appendTo('#qunit-fixture')
639+
640+
$toggleBtn.trigger('click')
641+
} catch (e) {
642+
done()
643+
}
640644
})
641645

642646
QUnit.test('should not try to open a modal which is already visible', function (assert) {

js/tests/unit/tab.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,8 @@ $(function () {
186186
'<ul class="drop nav">' +
187187
' <li class="dropdown"><a data-toggle="dropdown" href="#">1</a>' +
188188
' <ul class="dropdown-menu nav">' +
189-
' <li><a href="#1-1" data-toggle="tab">1-1</a></li>' +
190-
' <li><a href="#1-2" data-toggle="tab">1-2</a></li>' +
189+
' <li><a href="#a1-1" data-toggle="tab">1-1</a></li>' +
190+
' <li><a href="#a1-2" data-toggle="tab">1-2</a></li>' +
191191
' </ul>' +
192192
' </li>' +
193193
'</ul>'
@@ -198,10 +198,10 @@ $(function () {
198198
.end()
199199
.find('ul > li:last-child a')
200200
.on('show.bs.tab', function (e) {
201-
assert.strictEqual(e.relatedTarget.hash, '#1-1', 'references correct element as relatedTarget')
201+
assert.strictEqual(e.relatedTarget.hash, '#a1-1', 'references correct element as relatedTarget')
202202
})
203203
.on('shown.bs.tab', function (e) {
204-
assert.strictEqual(e.relatedTarget.hash, '#1-1', 'references correct element as relatedTarget')
204+
assert.strictEqual(e.relatedTarget.hash, '#a1-1', 'references correct element as relatedTarget')
205205
done()
206206
})
207207
.bootstrapTab('show')

js/tests/unit/util.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,19 @@ $(function () {
2020
assert.strictEqual(Util.getSelectorFromElement($el2[0]), null)
2121
})
2222

23+
QUnit.test('Util.getSelectorFromElement should throw error when there is a bad selector', function (assert) {
24+
assert.expect(2)
25+
26+
var $el = $('<div data-target="#1"></div>').appendTo($('#qunit-fixture'))
27+
28+
try {
29+
assert.ok(true, 'trying to use a bad selector')
30+
Util.getSelectorFromElement($el[0])
31+
} catch (e) {
32+
assert.ok(e instanceof DOMException)
33+
}
34+
})
35+
2336
QUnit.test('Util.typeCheckConfig should thrown an error when a bad config is passed', function (assert) {
2437
assert.expect(1)
2538
var namePlugin = 'collapse'

0 commit comments

Comments
 (0)