Added back escapeMarkup
This is needed to escape any bad markup that is passed through user-entered data. Users can prevent their markup from being escaped by using a no-op `escapeMarkup` function. This closes https://github.com/select2/select2/issues/2990.
This commit is contained in:
parent
01461813d8
commit
5a0f7f5518
26
dist/js/select2.amd.full.js
vendored
26
dist/js/select2.amd.full.js
vendored
@ -220,6 +220,22 @@ define(['jquery'], function ($) {define('select2/utils',[
|
||||
$el.innerWidth() < el.scrollWidth);
|
||||
};
|
||||
|
||||
Utils.escapeMarkup = function (markup) {
|
||||
var replaceMap = {
|
||||
'\\': '\',
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
'\'': ''',
|
||||
'/': '/'
|
||||
};
|
||||
|
||||
return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
|
||||
return replaceMap[match];
|
||||
});
|
||||
};
|
||||
|
||||
return Utils;
|
||||
});
|
||||
|
||||
@ -698,13 +714,14 @@ define('select2/results',[
|
||||
|
||||
Results.prototype.template = function (result, container) {
|
||||
var template = this.options.get('templateResult');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
var content = template(result);
|
||||
|
||||
if (content == null) {
|
||||
container.style.display = 'none';
|
||||
} else {
|
||||
container.innerHTML = content;
|
||||
container.innerHTML = escapeMarkup(content);
|
||||
}
|
||||
};
|
||||
|
||||
@ -942,8 +959,9 @@ define('select2/selection/single',[
|
||||
|
||||
SingleSelection.prototype.display = function (data) {
|
||||
var template = this.options.get('templateSelection');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
return template(data);
|
||||
return escapeMarkup(template(data));
|
||||
};
|
||||
|
||||
SingleSelection.prototype.selectionContainer = function () {
|
||||
@ -1020,8 +1038,9 @@ define('select2/selection/multiple',[
|
||||
|
||||
MultipleSelection.prototype.display = function (data) {
|
||||
var template = this.options.get('templateSelection');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
return template(data);
|
||||
return escapeMarkup(template(data));
|
||||
};
|
||||
|
||||
MultipleSelection.prototype.selectionContainer = function () {
|
||||
@ -3894,6 +3913,7 @@ define('select2/defaults',[
|
||||
this.defaults = {
|
||||
amdBase: 'select2/',
|
||||
amdLanguageBase: 'select2/i18n/',
|
||||
escapeMarkup: Utils.escapeMarkup,
|
||||
language: EnglishTranslation,
|
||||
matcher: matcher,
|
||||
minimumInputLength: 0,
|
||||
|
26
dist/js/select2.amd.js
vendored
26
dist/js/select2.amd.js
vendored
@ -220,6 +220,22 @@ define(['jquery'], function ($) {define('select2/utils',[
|
||||
$el.innerWidth() < el.scrollWidth);
|
||||
};
|
||||
|
||||
Utils.escapeMarkup = function (markup) {
|
||||
var replaceMap = {
|
||||
'\\': '\',
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
'\'': ''',
|
||||
'/': '/'
|
||||
};
|
||||
|
||||
return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
|
||||
return replaceMap[match];
|
||||
});
|
||||
};
|
||||
|
||||
return Utils;
|
||||
});
|
||||
|
||||
@ -698,13 +714,14 @@ define('select2/results',[
|
||||
|
||||
Results.prototype.template = function (result, container) {
|
||||
var template = this.options.get('templateResult');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
var content = template(result);
|
||||
|
||||
if (content == null) {
|
||||
container.style.display = 'none';
|
||||
} else {
|
||||
container.innerHTML = content;
|
||||
container.innerHTML = escapeMarkup(content);
|
||||
}
|
||||
};
|
||||
|
||||
@ -942,8 +959,9 @@ define('select2/selection/single',[
|
||||
|
||||
SingleSelection.prototype.display = function (data) {
|
||||
var template = this.options.get('templateSelection');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
return template(data);
|
||||
return escapeMarkup(template(data));
|
||||
};
|
||||
|
||||
SingleSelection.prototype.selectionContainer = function () {
|
||||
@ -1020,8 +1038,9 @@ define('select2/selection/multiple',[
|
||||
|
||||
MultipleSelection.prototype.display = function (data) {
|
||||
var template = this.options.get('templateSelection');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
return template(data);
|
||||
return escapeMarkup(template(data));
|
||||
};
|
||||
|
||||
MultipleSelection.prototype.selectionContainer = function () {
|
||||
@ -3894,6 +3913,7 @@ define('select2/defaults',[
|
||||
this.defaults = {
|
||||
amdBase: 'select2/',
|
||||
amdLanguageBase: 'select2/i18n/',
|
||||
escapeMarkup: Utils.escapeMarkup,
|
||||
language: EnglishTranslation,
|
||||
matcher: matcher,
|
||||
minimumInputLength: 0,
|
||||
|
26
dist/js/select2.full.js
vendored
26
dist/js/select2.full.js
vendored
@ -658,6 +658,22 @@ define('select2/utils',[
|
||||
$el.innerWidth() < el.scrollWidth);
|
||||
};
|
||||
|
||||
Utils.escapeMarkup = function (markup) {
|
||||
var replaceMap = {
|
||||
'\\': '\',
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
'\'': ''',
|
||||
'/': '/'
|
||||
};
|
||||
|
||||
return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
|
||||
return replaceMap[match];
|
||||
});
|
||||
};
|
||||
|
||||
return Utils;
|
||||
});
|
||||
|
||||
@ -1136,13 +1152,14 @@ define('select2/results',[
|
||||
|
||||
Results.prototype.template = function (result, container) {
|
||||
var template = this.options.get('templateResult');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
var content = template(result);
|
||||
|
||||
if (content == null) {
|
||||
container.style.display = 'none';
|
||||
} else {
|
||||
container.innerHTML = content;
|
||||
container.innerHTML = escapeMarkup(content);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1380,8 +1397,9 @@ define('select2/selection/single',[
|
||||
|
||||
SingleSelection.prototype.display = function (data) {
|
||||
var template = this.options.get('templateSelection');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
return template(data);
|
||||
return escapeMarkup(template(data));
|
||||
};
|
||||
|
||||
SingleSelection.prototype.selectionContainer = function () {
|
||||
@ -1458,8 +1476,9 @@ define('select2/selection/multiple',[
|
||||
|
||||
MultipleSelection.prototype.display = function (data) {
|
||||
var template = this.options.get('templateSelection');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
return template(data);
|
||||
return escapeMarkup(template(data));
|
||||
};
|
||||
|
||||
MultipleSelection.prototype.selectionContainer = function () {
|
||||
@ -4332,6 +4351,7 @@ define('select2/defaults',[
|
||||
this.defaults = {
|
||||
amdBase: 'select2/',
|
||||
amdLanguageBase: 'select2/i18n/',
|
||||
escapeMarkup: Utils.escapeMarkup,
|
||||
language: EnglishTranslation,
|
||||
matcher: matcher,
|
||||
minimumInputLength: 0,
|
||||
|
4
dist/js/select2.full.min.js
vendored
4
dist/js/select2.full.min.js
vendored
File diff suppressed because one or more lines are too long
26
dist/js/select2.js
vendored
26
dist/js/select2.js
vendored
@ -658,6 +658,22 @@ define('select2/utils',[
|
||||
$el.innerWidth() < el.scrollWidth);
|
||||
};
|
||||
|
||||
Utils.escapeMarkup = function (markup) {
|
||||
var replaceMap = {
|
||||
'\\': '\',
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
'\'': ''',
|
||||
'/': '/'
|
||||
};
|
||||
|
||||
return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
|
||||
return replaceMap[match];
|
||||
});
|
||||
};
|
||||
|
||||
return Utils;
|
||||
});
|
||||
|
||||
@ -1136,13 +1152,14 @@ define('select2/results',[
|
||||
|
||||
Results.prototype.template = function (result, container) {
|
||||
var template = this.options.get('templateResult');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
var content = template(result);
|
||||
|
||||
if (content == null) {
|
||||
container.style.display = 'none';
|
||||
} else {
|
||||
container.innerHTML = content;
|
||||
container.innerHTML = escapeMarkup(content);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1380,8 +1397,9 @@ define('select2/selection/single',[
|
||||
|
||||
SingleSelection.prototype.display = function (data) {
|
||||
var template = this.options.get('templateSelection');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
return template(data);
|
||||
return escapeMarkup(template(data));
|
||||
};
|
||||
|
||||
SingleSelection.prototype.selectionContainer = function () {
|
||||
@ -1458,8 +1476,9 @@ define('select2/selection/multiple',[
|
||||
|
||||
MultipleSelection.prototype.display = function (data) {
|
||||
var template = this.options.get('templateSelection');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
return template(data);
|
||||
return escapeMarkup(template(data));
|
||||
};
|
||||
|
||||
MultipleSelection.prototype.selectionContainer = function () {
|
||||
@ -4332,6 +4351,7 @@ define('select2/defaults',[
|
||||
this.defaults = {
|
||||
amdBase: 'select2/',
|
||||
amdLanguageBase: 'select2/i18n/',
|
||||
escapeMarkup: Utils.escapeMarkup,
|
||||
language: EnglishTranslation,
|
||||
matcher: matcher,
|
||||
minimumInputLength: 0,
|
||||
|
4
dist/js/select2.min.js
vendored
4
dist/js/select2.min.js
vendored
File diff suppressed because one or more lines are too long
@ -229,6 +229,7 @@ $(".js-data-example-ajax").select2({
|
||||
},
|
||||
cache: true
|
||||
},
|
||||
escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
|
||||
minimumInputLength: 1,
|
||||
templateResult: formatRepo, // omitted for brevity, see the source of this page
|
||||
templateSelection: formatRepoSelection // omitted for brevity, see the source of this page
|
||||
@ -949,6 +950,7 @@ $.fn.select2.amd.require(
|
||||
},
|
||||
cache: true
|
||||
},
|
||||
escapeMarkup: function (markup) { return markup; },
|
||||
minimumInputLength: 1,
|
||||
templateResult: function (repo) {
|
||||
if (repo.loading) return repo.text;
|
||||
|
1
src/js/select2/defaults.js
vendored
1
src/js/select2/defaults.js
vendored
@ -309,6 +309,7 @@ define([
|
||||
this.defaults = {
|
||||
amdBase: 'select2/',
|
||||
amdLanguageBase: 'select2/i18n/',
|
||||
escapeMarkup: Utils.escapeMarkup,
|
||||
language: EnglishTranslation,
|
||||
matcher: matcher,
|
||||
minimumInputLength: 0,
|
||||
|
3
src/js/select2/results.js
vendored
3
src/js/select2/results.js
vendored
@ -473,13 +473,14 @@ define([
|
||||
|
||||
Results.prototype.template = function (result, container) {
|
||||
var template = this.options.get('templateResult');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
var content = template(result);
|
||||
|
||||
if (content == null) {
|
||||
container.style.display = 'none';
|
||||
} else {
|
||||
container.innerHTML = content;
|
||||
container.innerHTML = escapeMarkup(content);
|
||||
}
|
||||
};
|
||||
|
||||
|
3
src/js/select2/selection/multiple.js
vendored
3
src/js/select2/selection/multiple.js
vendored
@ -52,8 +52,9 @@ define([
|
||||
|
||||
MultipleSelection.prototype.display = function (data) {
|
||||
var template = this.options.get('templateSelection');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
return template(data);
|
||||
return escapeMarkup(template(data));
|
||||
};
|
||||
|
||||
MultipleSelection.prototype.selectionContainer = function () {
|
||||
|
3
src/js/select2/selection/single.js
vendored
3
src/js/select2/selection/single.js
vendored
@ -65,8 +65,9 @@ define([
|
||||
|
||||
SingleSelection.prototype.display = function (data) {
|
||||
var template = this.options.get('templateSelection');
|
||||
var escapeMarkup = this.options.get('escapeMarkup');
|
||||
|
||||
return template(data);
|
||||
return escapeMarkup(template(data));
|
||||
};
|
||||
|
||||
SingleSelection.prototype.selectionContainer = function () {
|
||||
|
16
src/js/select2/utils.js
vendored
16
src/js/select2/utils.js
vendored
@ -220,5 +220,21 @@ define([
|
||||
$el.innerWidth() < el.scrollWidth);
|
||||
};
|
||||
|
||||
Utils.escapeMarkup = function (markup) {
|
||||
var replaceMap = {
|
||||
'\\': '\',
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
'\'': ''',
|
||||
'/': '/'
|
||||
};
|
||||
|
||||
return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
|
||||
return replaceMap[match];
|
||||
});
|
||||
};
|
||||
|
||||
return Utils;
|
||||
});
|
||||
|
@ -48,3 +48,25 @@ test('empty update clears the selection', function (assert) {
|
||||
|
||||
assert.equal($rendered.text(), '');
|
||||
});
|
||||
|
||||
test('escapePlaceholder is being used', function (assert) {
|
||||
var selection = new MultipleSelection(
|
||||
$('#qunit-fixture .multiple'),
|
||||
options
|
||||
);
|
||||
|
||||
var $selection = selection.render();
|
||||
var $rendered = $selection.find('.select2-selection__rendered');
|
||||
|
||||
var unescapedText = '<script>bad("stuff");</script>';
|
||||
|
||||
selection.update([{
|
||||
text: unescapedText
|
||||
}]);
|
||||
|
||||
assert.equal(
|
||||
$rendered.text().indexOf(unescapedText),
|
||||
1,
|
||||
'The text should be escaped by default to prevent injection'
|
||||
);
|
||||
});
|
||||
|
@ -64,3 +64,25 @@ test('update renders the data text', function (assert) {
|
||||
|
||||
assert.equal($rendered.text(), 'test');
|
||||
});
|
||||
|
||||
test('escapePlaceholder is being used', function (assert) {
|
||||
var selection = new SingleSelection(
|
||||
$('#qunit-fixture .single'),
|
||||
options
|
||||
);
|
||||
|
||||
var $selection = selection.render();
|
||||
var $rendered = $selection.find('.select2-selection__rendered');
|
||||
|
||||
var unescapedText = '<script>bad("stuff");</script>';
|
||||
|
||||
selection.update([{
|
||||
text: unescapedText
|
||||
}]);
|
||||
|
||||
assert.equal(
|
||||
$rendered.text(),
|
||||
unescapedText,
|
||||
'The text should be escaped by default to prevent injection'
|
||||
);
|
||||
});
|
||||
|
27
tests/utils/escapeMarkup-tests.js
Normal file
27
tests/utils/escapeMarkup-tests.js
Normal file
@ -0,0 +1,27 @@
|
||||
module('Utils - escapeMarkup');
|
||||
|
||||
var Utils = require('select2/utils');
|
||||
|
||||
test('text passes through', function (assert) {
|
||||
var text = 'testing this';
|
||||
var escaped = Utils.escapeMarkup(text);
|
||||
|
||||
assert.equal(text, escaped);
|
||||
});
|
||||
|
||||
test('html tags are escaped', function (assert) {
|
||||
var text = '<script>alert("bad");</script>';
|
||||
var escaped = Utils.escapeMarkup(text);
|
||||
|
||||
assert.notEqual(text, escaped);
|
||||
assert.equal(escaped.indexOf('<script>'), -1);
|
||||
});
|
||||
|
||||
test('quotes are killed as well', function (assert) {
|
||||
var text = 'testin\' these "quotes"';
|
||||
var escaped = Utils.escapeMarkup(text);
|
||||
|
||||
assert.notEqual(text, escaped);
|
||||
assert.equal(escaped.indexOf('\''), -1);
|
||||
assert.equal(escaped.indexOf('"'), -1);
|
||||
});
|
19
tests/utils/escapeMarkup.html
Normal file
19
tests/utils/escapeMarkup.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="../vendor/qunit-1.14.0.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../dist/css/select2.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture"></div>
|
||||
|
||||
<script src="../vendor/qunit-1.14.0.js" type="text/javascript"></script>
|
||||
<script src="../../vendor/jquery-2.1.0.js" type="text/javascript"></script>
|
||||
<script src="../../dist/js/select2.full.js" type="text/javascript"></script>
|
||||
|
||||
<script src="../helpers.js" type="text/javascript"></script>
|
||||
|
||||
<script src="escapeMarkup-tests.js" type="text/javascript"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user