Stored Cross-site Scripting in Client's Name #1727

This commit is contained in:
Hillel Coren 2017-10-30 16:00:55 +02:00
parent 5e7f6a029b
commit dbd19d4174
12 changed files with 42 additions and 52 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -460,7 +460,7 @@ if (window.ko) {
function comboboxHighlighter(item) { function comboboxHighlighter(item) {
var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
var result = item.replace(new RegExp('<br/>', 'g'), "\n"); var result = item.replace(new RegExp('<br/>', 'g'), "\n");
result = stripHtmlTags(result); result = _.escape(result);
result = result.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { result = result.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
return match ? '<strong>' + match + '</strong>' : query; return match ? '<strong>' + match + '</strong>' : query;
}); });
@ -476,17 +476,6 @@ function inIframe () {
} }
} }
function comboboxMatcher(item) {
return ~stripHtmlTags(item).toLowerCase().indexOf(this.query.toLowerCase());
}
function stripHtmlTags(text) {
// http://stackoverflow.com/a/5002618/497368
var div = document.createElement("div");
div.innerHTML = text;
return div.textContent || div.innerText || '';
}
function getContactDisplayName(contact) function getContactDisplayName(contact)
{ {
if (contact.first_name || contact.last_name) { if (contact.first_name || contact.last_name) {
@ -563,7 +552,7 @@ function populateInvoiceComboboxes(clientId, invoiceId) {
$clientSelect.val(clientId); $clientSelect.val(clientId);
} }
$clientSelect.combobox(); $clientSelect.combobox({highlighter: comboboxHighlighter});
$clientSelect.on('change', function(e) { $clientSelect.on('change', function(e) {
var clientId = $('input[name=client]').val(); var clientId = $('input[name=client]').val();
var invoiceId = $('input[name=invoice]').val(); var invoiceId = $('input[name=invoice]').val();
@ -602,7 +591,7 @@ function populateInvoiceComboboxes(clientId, invoiceId) {
} }
}); });
$invoiceSelect.combobox(); $invoiceSelect.combobox({highlighter: comboboxHighlighter});
if (invoiceId) { if (invoiceId) {
var invoice = invoiceMap[invoiceId]; var invoice = invoiceMap[invoiceId];

View File

@ -381,7 +381,7 @@ iframe.src = '{{ rtrim(SITE_URL ,'/') }}/view/'
$productSelect.append(new Option(formatMoney(product.cost) + ' - ' + product.product_key, product.public_id)); $productSelect.append(new Option(formatMoney(product.cost) + ' - ' + product.product_key, product.public_id));
} }
$productSelect.combobox(); $productSelect.combobox({highlighter: comboboxHighlighter});
fixCheckboxes(); fixCheckboxes();
updateBuyNowButtons(); updateBuyNowButtons();

View File

@ -80,7 +80,7 @@
$clientSelect.val({{ $clientPublicId }}); $clientSelect.val({{ $clientPublicId }});
} }
$clientSelect.combobox(); $clientSelect.combobox({highlighter: comboboxHighlighter});
@endif @endif
$('#currency_id').combobox(); $('#currency_id').combobox();

View File

@ -350,7 +350,7 @@
} }
$clientSelect.append(new Option(clientName, client.public_id)); $clientSelect.append(new Option(clientName, client.public_id));
} }
$clientSelect.combobox().change(function() { $clientSelect.combobox({highlighter: comboboxHighlighter}).change(function() {
onClientChange(); onClientChange();
}); });

View File

@ -113,7 +113,7 @@
{!! Former::select('client') {!! Former::select('client')
->addOption('', '') ->addOption('', '')
->data_bind("dropdown: client, dropdownOptions: {highlighter: comboboxHighlighter, matcher: comboboxMatcher}") ->data_bind("dropdown: client, dropdownOptions: {highlighter: comboboxHighlighter}")
->addClass('client-input') ->addClass('client-input')
->addGroupClass('client_select closer-row') !!} ->addGroupClass('client_select closer-row') !!}

View File

@ -1006,10 +1006,10 @@ ko.bindingHandlers.productTypeahead = {
limit: 50, limit: 50,
templates: { templates: {
suggestion: function(item) { return '<div title="' suggestion: function(item) { return '<div title="'
+ item.product_key + ': ' + _.escape(item.product_key) + ': '
+ item.cost + "\n" + item.cost + "\n"
+ item.notes.substring(0, 60) + '">' + item.notes.substring(0, 60) + '">'
+ item.product_key + '</div>' } + _.escape(item.product_key) + '</div>' }
}, },
source: searchData(allBindings.items, allBindings.key) source: searchData(allBindings.items, allBindings.key)
}).on('typeahead:select', function(element, datum, name) { }).on('typeahead:select', function(element, datum, name) {

View File

@ -7,8 +7,9 @@ ${{ $entityType }}Select.combobox({
return "{{ trans("texts.create_{$entityType}") }}: " + this.query; return "{{ trans("texts.create_{$entityType}") }}: " + this.query;
} else { } else {
var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
item = _.escape(item);
return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
return '<strong>' + match + '</strong>'; return match ? '<strong>' + match + '</strong>' : query;
}) })
} }
}, },

View File

@ -80,7 +80,7 @@
$clientSelect.val({{ $clientPublicId }}); $clientSelect.val({{ $clientPublicId }});
@endif @endif
$clientSelect.combobox(); $clientSelect.combobox({highlighter: comboboxHighlighter});
@if ($clientPublicId) @if ($clientPublicId)
$('#name').focus(); $('#name').focus();

View File

@ -566,7 +566,7 @@
$clientSelect.val(clientId); $clientSelect.val(clientId);
} }
$clientSelect.combobox(); $clientSelect.combobox({highlighter: comboboxHighlighter});
$clientSelect.on('change', function(e) { $clientSelect.on('change', function(e) {
var clientId = $('input[name=client]').val(); var clientId = $('input[name=client]').val();
var projectId = $('input[name=project_id]').val(); var projectId = $('input[name=project_id]').val();

View File

@ -205,12 +205,12 @@
{!! Former::select('client_id') {!! Former::select('client_id')
->addOption('', '') ->addOption('', '')
->label('client') ->label('client')
->data_bind("dropdown: selectedTask().client_id") !!} ->data_bind("dropdown: selectedTask().client_id, dropdownOptions: {highlighter: comboboxHighlighter}") !!}
</div> </div>
<div style="padding-bottom: 20px; padding-left:6px;" class="project-select col-md-6 no-padding-mobile"> <div style="padding-bottom: 20px; padding-left:6px;" class="project-select col-md-6 no-padding-mobile">
{!! Former::select('project_id') {!! Former::select('project_id')
->addOption('', '') ->addOption('', '')
->data_bind("dropdown: selectedTask().project_id") ->data_bind("dropdown: selectedTask().project_id, dropdownOptions: {highlighter: comboboxHighlighter}")
->label(trans('texts.project')) !!} ->label(trans('texts.project')) !!}
</div> </div>
</div> </div>
@ -395,7 +395,7 @@
function refreshClientList() { function refreshClientList() {
var $clientSelect = $('select#client_id'); var $clientSelect = $('select#client_id');
$clientSelect.find('option').remove().end().combobox('refresh'); $clientSelect.combobox({highlighter: comboboxHighlighter}).find('option').remove().end().combobox('refresh');
$clientSelect.append(new Option('', '')); $clientSelect.append(new Option('', ''));
@if (Auth::user()->can('create', ENTITY_CLIENT)) @if (Auth::user()->can('create', ENTITY_CLIENT))