1
0
mirror of synced 2025-02-09 16:49:24 +03:00

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:
Kevin Brown 2015-01-29 08:41:18 -05:00
parent 01461813d8
commit 5a0f7f5518
16 changed files with 211 additions and 19 deletions

View File

@ -220,6 +220,22 @@ define(['jquery'], function ($) {define('select2/utils',[
$el.innerWidth() < el.scrollWidth);
};
Utils.escapeMarkup = function (markup) {
var replaceMap = {
'\\': '&#92;',
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'\'': '&#39;',
'/': '&#47;'
};
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,

View File

@ -220,6 +220,22 @@ define(['jquery'], function ($) {define('select2/utils',[
$el.innerWidth() < el.scrollWidth);
};
Utils.escapeMarkup = function (markup) {
var replaceMap = {
'\\': '&#92;',
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'\'': '&#39;',
'/': '&#47;'
};
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,

View File

@ -658,6 +658,22 @@ define('select2/utils',[
$el.innerWidth() < el.scrollWidth);
};
Utils.escapeMarkup = function (markup) {
var replaceMap = {
'\\': '&#92;',
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'\'': '&#39;',
'/': '&#47;'
};
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,

File diff suppressed because one or more lines are too long

26
dist/js/select2.js vendored
View File

@ -658,6 +658,22 @@ define('select2/utils',[
$el.innerWidth() < el.scrollWidth);
};
Utils.escapeMarkup = function (markup) {
var replaceMap = {
'\\': '&#92;',
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'\'': '&#39;',
'/': '&#47;'
};
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,

File diff suppressed because one or more lines are too long

View File

@ -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;

View File

@ -309,6 +309,7 @@ define([
this.defaults = {
amdBase: 'select2/',
amdLanguageBase: 'select2/i18n/',
escapeMarkup: Utils.escapeMarkup,
language: EnglishTranslation,
matcher: matcher,
minimumInputLength: 0,

View File

@ -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);
}
};

View File

@ -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 () {

View File

@ -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 () {

View File

@ -220,5 +220,21 @@ define([
$el.innerWidth() < el.scrollWidth);
};
Utils.escapeMarkup = function (markup) {
var replaceMap = {
'\\': '&#92;',
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
'\'': '&#39;',
'/': '&#47;'
};
return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
return replaceMap[match];
});
};
return Utils;
});

View File

@ -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'
);
});

View File

@ -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'
);
});

View 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);
});

View 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>