updated core to 7.58, security update

This commit is contained in:
2018-04-24 23:28:54 +02:00
parent 83a28c5dc3
commit dc21b82664
357 changed files with 10830 additions and 2674 deletions
+34 -6
View File
@@ -14,6 +14,8 @@
Drupal.ajax = Drupal.ajax || {};
Drupal.settings.urlIsAjaxTrusted = Drupal.settings.urlIsAjaxTrusted || {};
/**
* Attaches the Ajax behavior to each Ajax form element.
*/
@@ -130,6 +132,11 @@ Drupal.ajax = function (base, element, element_settings) {
// 5. /nojs# - Followed by a fragment.
// E.g.: path/nojs#myfragment
this.url = element_settings.url.replace(/\/nojs(\/|$|\?|&|#)/g, '/ajax$1');
// If the 'nojs' version of the URL is trusted, also trust the 'ajax' version.
if (Drupal.settings.urlIsAjaxTrusted[element_settings.url]) {
Drupal.settings.urlIsAjaxTrusted[this.url] = true;
}
this.wrapper = '#' + element_settings.wrapper;
// If there isn't a form, jQuery.ajax() will be used instead, allowing us to
@@ -155,18 +162,36 @@ Drupal.ajax = function (base, element, element_settings) {
ajax.ajaxing = true;
return ajax.beforeSend(xmlhttprequest, options);
},
success: function (response, status) {
success: function (response, status, xmlhttprequest) {
// Sanity check for browser support (object expected).
// When using iFrame uploads, responses must be returned as a string.
if (typeof response == 'string') {
response = $.parseJSON(response);
}
// Prior to invoking the response's commands, verify that they can be
// trusted by checking for a response header. See
// ajax_set_verification_header() for details.
// - Empty responses are harmless so can bypass verification. This avoids
// an alert message for server-generated no-op responses that skip Ajax
// rendering.
// - Ajax objects with trusted URLs (e.g., ones defined server-side via
// #ajax) can bypass header verification. This is especially useful for
// Ajax with multipart forms. Because IFRAME transport is used, the
// response headers cannot be accessed for verification.
if (response !== null && !Drupal.settings.urlIsAjaxTrusted[ajax.url]) {
if (xmlhttprequest.getResponseHeader('X-Drupal-Ajax-Token') !== '1') {
var customMessage = Drupal.t("The response failed verification so will not be processed.");
return ajax.error(xmlhttprequest, ajax.url, customMessage);
}
}
return ajax.success(response, status);
},
complete: function (response, status) {
complete: function (xmlhttprequest, status) {
ajax.ajaxing = false;
if (status == 'error' || status == 'parsererror') {
return ajax.error(response, ajax.url);
return ajax.error(xmlhttprequest, ajax.url);
}
},
dataType: 'json',
@@ -175,6 +200,9 @@ Drupal.ajax = function (base, element, element_settings) {
// Bind the ajaxSubmit function to the element event.
$(ajax.element).bind(element_settings.event, function (event) {
if (!Drupal.settings.urlIsAjaxTrusted[ajax.url] && !Drupal.urlIsLocal(ajax.url)) {
throw new Error(Drupal.t('The callback URL is not local and not trusted: !url', {'!url': ajax.url}));
}
return ajax.eventResponse(this, event);
});
@@ -447,8 +475,8 @@ Drupal.ajax.prototype.getEffect = function (response) {
/**
* Handler for the form redirection error.
*/
Drupal.ajax.prototype.error = function (response, uri) {
alert(Drupal.ajaxError(response, uri));
Drupal.ajax.prototype.error = function (xmlhttprequest, uri, customMessage) {
Drupal.displayAjaxError(Drupal.ajaxError(xmlhttprequest, uri, customMessage));
// Remove the progress element.
if (this.progress.element) {
$(this.progress.element).remove();
@@ -462,7 +490,7 @@ Drupal.ajax.prototype.error = function (response, uri) {
$(this.element).removeClass('progress-disabled').removeAttr('disabled');
// Reattach behaviors, if they were detached in beforeSerialize().
if (this.form) {
var settings = response.settings || this.settings || Drupal.settings;
var settings = this.settings || Drupal.settings;
Drupal.attachBehaviors(this.form, settings);
}
};
+9 -5
View File
@@ -114,6 +114,7 @@ Drupal.jsAC.prototype.onkeyup = function (input, e) {
*/
Drupal.jsAC.prototype.select = function (node) {
this.input.value = $(node).data('autocompleteValue');
$(this.input).trigger('autocompleteSelect', [node]);
};
/**
@@ -167,7 +168,7 @@ Drupal.jsAC.prototype.unhighlight = function (node) {
Drupal.jsAC.prototype.hidePopup = function (keycode) {
// Select item if the right key or mousebutton was pressed.
if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
this.input.value = $(this.selected).data('autocompleteValue');
this.select(this.selected);
}
// Hide popup.
var popup = this.popup;
@@ -220,7 +221,7 @@ Drupal.jsAC.prototype.found = function (matches) {
for (key in matches) {
$('<li></li>')
.html($('<div></div>').html(matches[key]))
.mousedown(function () { ac.select(this); })
.mousedown(function () { ac.hidePopup(this); })
.mouseover(function () { ac.highlight(this); })
.mouseout(function () { ac.unhighlight(this); })
.data('autocompleteValue', key)
@@ -270,8 +271,11 @@ Drupal.ACDB.prototype.search = function (searchString) {
var db = this;
this.searchString = searchString;
// See if this string needs to be searched for anyway.
searchString = searchString.replace(/^\s+|\s+$/, '');
// See if this string needs to be searched for anyway. The pattern ../ is
// stripped since it may be misinterpreted by the browser.
searchString = searchString.replace(/^\s+|\.{2,}\/|\s+$/g, '');
// Skip empty search strings, or search strings ending with a comma, since
// that is the separator between search terms.
if (searchString.length <= 0 ||
searchString.charAt(searchString.length - 1) == ',') {
return;
@@ -306,7 +310,7 @@ Drupal.ACDB.prototype.search = function (searchString) {
}
},
error: function (xmlhttp) {
alert(Drupal.ajaxError(xmlhttp, db.uri));
Drupal.displayAjaxError(Drupal.ajaxError(xmlhttp, db.uri));
}
});
}, this.delay);
+200 -19
View File
@@ -27,6 +27,42 @@ $.fn.init = function (selector, context, rootjQuery) {
};
$.fn.init.prototype = jquery_init.prototype;
/**
* Pre-filter Ajax requests to guard against XSS attacks.
*
* See https://github.com/jquery/jquery/issues/2432
*/
if ($.ajaxPrefilter) {
// For newer versions of jQuery, use an Ajax prefilter to prevent
// auto-executing script tags from untrusted domains. This is similar to the
// fix that is built in to jQuery 3.0 and higher.
$.ajaxPrefilter(function (s) {
if (s.crossDomain) {
s.contents.script = false;
}
});
}
else if ($.httpData) {
// For the version of jQuery that ships with Drupal core, override
// jQuery.httpData to prevent auto-detecting "script" data types from
// untrusted domains.
var jquery_httpData = $.httpData;
$.httpData = function (xhr, type, s) {
// @todo Consider backporting code from newer jQuery versions to check for
// a cross-domain request here, rather than using Drupal.urlIsLocal() to
// block scripts from all URLs that are not on the same site.
if (!type && !Drupal.urlIsLocal(s.url)) {
var content_type = xhr.getResponseHeader('content-type') || '';
if (content_type.indexOf('javascript') >= 0) {
// Default to a safe data type.
type = 'text';
}
}
return jquery_httpData.call(this, xhr, type, s);
};
$.httpData.prototype = jquery_httpData.prototype;
}
/**
* Attach all registered behaviors to a page element.
*
@@ -137,7 +173,7 @@ Drupal.detachBehaviors = function (context, settings, trigger) {
*/
Drupal.checkPlain = function (str) {
var character, regex,
replace = { '&': '&amp;', '"': '&quot;', '<': '&lt;', '>': '&gt;' };
replace = { '&': '&amp;', "'": '&#39;', '"': '&quot;', '<': '&lt;', '>': '&gt;' };
str = String(str);
for (character in replace) {
if (replace.hasOwnProperty(character)) {
@@ -168,23 +204,76 @@ Drupal.checkPlain = function (str) {
Drupal.formatString = function(str, args) {
// Transform arguments before inserting them.
for (var key in args) {
switch (key.charAt(0)) {
// Escaped only.
case '@':
args[key] = Drupal.checkPlain(args[key]);
break;
// Pass-through.
case '!':
break;
// Escaped and placeholder.
case '%':
default:
args[key] = Drupal.theme('placeholder', args[key]);
break;
if (args.hasOwnProperty(key)) {
switch (key.charAt(0)) {
// Escaped only.
case '@':
args[key] = Drupal.checkPlain(args[key]);
break;
// Pass-through.
case '!':
break;
// Escaped and placeholder.
default:
args[key] = Drupal.theme('placeholder', args[key]);
break;
}
}
str = str.replace(key, args[key]);
}
return str;
return Drupal.stringReplace(str, args, null);
};
/**
* Replace substring.
*
* The longest keys will be tried first. Once a substring has been replaced,
* its new value will not be searched again.
*
* @param {String} str
* A string with placeholders.
* @param {Object} args
* Key-value pairs.
* @param {Array|null} keys
* Array of keys from the "args". Internal use only.
*
* @return {String}
* Returns the replaced string.
*/
Drupal.stringReplace = function (str, args, keys) {
if (str.length === 0) {
return str;
}
// If the array of keys is not passed then collect the keys from the args.
if (!$.isArray(keys)) {
keys = [];
for (var k in args) {
if (args.hasOwnProperty(k)) {
keys.push(k);
}
}
// Order the keys by the character length. The shortest one is the first.
keys.sort(function (a, b) { return a.length - b.length; });
}
if (keys.length === 0) {
return str;
}
// Take next longest one from the end.
var key = keys.pop();
var fragments = str.split(key);
if (keys.length) {
for (var i = 0; i < fragments.length; i++) {
// Process each fragment with a copy of remaining keys.
fragments[i] = Drupal.stringReplace(fragments[i], args, keys.slice(0));
}
}
return fragments.join(args[key]);
};
/**
@@ -251,7 +340,7 @@ Drupal.t = function (str, args, options) {
* A translated string.
*/
Drupal.formatPlural = function (count, singular, plural, args, options) {
var args = args || {};
args = args || {};
args['@count'] = count;
// Determine the index of the plural form.
var index = Drupal.locale.pluralFormula ? Drupal.locale.pluralFormula(args['@count']) : ((args['@count'] == 1) ? 0 : 1);
@@ -269,6 +358,72 @@ Drupal.formatPlural = function (count, singular, plural, args, options) {
}
};
/**
* Returns the passed in URL as an absolute URL.
*
* @param url
* The URL string to be normalized to an absolute URL.
*
* @return
* The normalized, absolute URL.
*
* @see https://github.com/angular/angular.js/blob/v1.4.4/src/ng/urlUtils.js
* @see https://grack.com/blog/2009/11/17/absolutizing-url-in-javascript
* @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L53
*/
Drupal.absoluteUrl = function (url) {
var urlParsingNode = document.createElement('a');
// Decode the URL first; this is required by IE <= 6. Decoding non-UTF-8
// strings may throw an exception.
try {
url = decodeURIComponent(url);
} catch (e) {}
urlParsingNode.setAttribute('href', url);
// IE <= 7 normalizes the URL when assigned to the anchor node similar to
// the other browsers.
return urlParsingNode.cloneNode(false).href;
};
/**
* Returns true if the URL is within Drupal's base path.
*
* @param url
* The URL string to be tested.
*
* @return
* Boolean true if local.
*
* @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L58
*/
Drupal.urlIsLocal = function (url) {
// Always use browser-derived absolute URLs in the comparison, to avoid
// attempts to break out of the base path using directory traversal.
var absoluteUrl = Drupal.absoluteUrl(url);
var protocol = location.protocol;
// Consider URLs that match this site's base URL but use HTTPS instead of HTTP
// as local as well.
if (protocol === 'http:' && absoluteUrl.indexOf('https:') === 0) {
protocol = 'https:';
}
var baseUrl = protocol + '//' + location.host + Drupal.settings.basePath.slice(0, -1);
// Decoding non-UTF-8 strings may throw an exception.
try {
absoluteUrl = decodeURIComponent(absoluteUrl);
} catch (e) {}
try {
baseUrl = decodeURIComponent(baseUrl);
} catch (e) {}
// The given URL matches the site's base URL, or has a path under the site's
// base URL.
return absoluteUrl === baseUrl || absoluteUrl.indexOf(baseUrl + '/') === 0;
};
/**
* Generate the themed representation of a Drupal object.
*
@@ -347,10 +502,33 @@ Drupal.getSelection = function (element) {
return { 'start': element.selectionStart, 'end': element.selectionEnd };
};
/**
* Add a global variable which determines if the window is being unloaded.
*
* This is primarily used by Drupal.displayAjaxError().
*/
Drupal.beforeUnloadCalled = false;
$(window).bind('beforeunload pagehide', function () {
Drupal.beforeUnloadCalled = true;
});
/**
* Displays a JavaScript error from an Ajax response when appropriate to do so.
*/
Drupal.displayAjaxError = function (message) {
// Skip displaying the message if the user deliberately aborted (for example,
// by reloading the page or navigating to a different page) while the Ajax
// request was still ongoing. See, for example, the discussion at
// http://stackoverflow.com/questions/699941/handle-ajax-error-when-a-user-clicks-refresh.
if (!Drupal.beforeUnloadCalled) {
alert(message);
}
};
/**
* Build an error message from an Ajax response.
*/
Drupal.ajaxError = function (xmlhttp, uri) {
Drupal.ajaxError = function (xmlhttp, uri, customMessage) {
var statusCode, statusText, pathText, responseText, readyStateText, message;
if (xmlhttp.status) {
statusCode = "\n" + Drupal.t("An AJAX HTTP error occurred.") + "\n" + Drupal.t("HTTP Result Code: !status", {'!status': xmlhttp.status});
@@ -383,7 +561,10 @@ Drupal.ajaxError = function (xmlhttp, uri) {
// We don't need readyState except for status == 0.
readyStateText = xmlhttp.status == 0 ? ("\n" + Drupal.t("ReadyState: !readyState", {'!readyState': xmlhttp.readyState})) : "";
message = statusCode + pathText + statusText + responseText + readyStateText;
// Additional message beyond what the xmlhttp object provides.
customMessage = customMessage ? ("\n" + Drupal.t("CustomMessage: !customMessage", {'!customMessage': customMessage})) : "";
message = statusCode + pathText + statusText + customMessage + responseText + readyStateText;
return message;
};
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

+5 -1
View File
@@ -493,7 +493,11 @@ $(document).bind('state:disabled', function(e) {
$(document).bind('state:required', function(e) {
if (e.trigger) {
if (e.value) {
$(e.target).closest('.form-item, .form-wrapper').find('label').append('<span class="form-required">*</span>');
var $label = $(e.target).closest('.form-item, .form-wrapper').find('label');
// Avoids duplicate required markers on initialization.
if (!$label.find('.form-required').length) {
$label.append('<span class="form-required">*</span>');
}
}
else {
$(e.target).closest('.form-item, .form-wrapper').find('label .form-required').remove();
+19 -6
View File
@@ -106,8 +106,10 @@ Drupal.tableDrag = function (table, tableSettings) {
// Add mouse bindings to the document. The self variable is passed along
// as event handlers do not have direct access to the tableDrag object.
$(document).bind('mousemove', function (event) { return self.dragRow(event, self); });
$(document).bind('mouseup', function (event) { return self.dropRow(event, self); });
$(document).bind('mousemove pointermove', function (event) { return self.dragRow(event, self); });
$(document).bind('mouseup pointerup', function (event) { return self.dropRow(event, self); });
$(document).bind('touchmove', function (event) { return self.dragRow(event.originalEvent.touches[0], self); });
$(document).bind('touchend', function (event) { return self.dropRow(event.originalEvent.touches[0], self); });
};
/**
@@ -274,7 +276,10 @@ Drupal.tableDrag.prototype.makeDraggable = function (item) {
});
// Add the mousedown action for the handle.
handle.mousedown(function (event) {
handle.bind('mousedown touchstart pointerdown', function (event) {
if (event.originalEvent.type == "touchstart") {
event = event.originalEvent.touches[0];
}
// Create a new dragObject recording the event information.
self.dragObject = {};
self.dragObject.initMouseOffset = self.getMouseOffset(item, event);
@@ -500,7 +505,7 @@ Drupal.tableDrag.prototype.dragRow = function (event, self) {
if (self.indentEnabled) {
var xDiff = self.currentMouseCoords.x - self.dragObject.indentMousePos.x;
// Set the number of indentations the mouse has been moved left or right.
var indentDiff = Math.round(xDiff / self.indentAmount * self.rtl);
var indentDiff = Math.round(xDiff / self.indentAmount);
// Indent the row with our estimated diff, which may be further
// restricted according to the rows around this row.
var indentChange = self.rowObject.indent(indentDiff);
@@ -575,12 +580,20 @@ Drupal.tableDrag.prototype.dropRow = function (event, self) {
* Get the mouse coordinates from the event (allowing for browser differences).
*/
Drupal.tableDrag.prototype.mouseCoords = function (event) {
// Complete support for pointer events was only introduced to jQuery in
// version 1.11.1; between versions 1.7 and 1.11.0 pointer events have the
// clientX and clientY properties undefined. In those cases, the properties
// must be retrieved from the event.originalEvent object instead.
var clientX = event.clientX || event.originalEvent.clientX;
var clientY = event.clientY || event.originalEvent.clientY;
if (event.pageX || event.pageY) {
return { x: event.pageX, y: event.pageY };
}
return {
x: event.clientX + document.body.scrollLeft - document.body.clientLeft,
y: event.clientY + document.body.scrollTop - document.body.clientTop
x: clientX + document.body.scrollLeft - document.body.clientLeft,
y: clientY + document.body.scrollTop - document.body.clientTop
};
};
+5 -1
View File
@@ -57,10 +57,14 @@ Drupal.tableSelect = function () {
// Keep track of the last checked checkbox.
lastChecked = e.target;
});
// If all checkboxes are checked on page load, make sure the select-all one
// is checked too, otherwise keep unchecked.
updateSelectAll((checkboxes.length == $(checkboxes).filter(':checked').length));
};
Drupal.tableSelectRange = function (from, to, state) {
// We determine the looping mode based on the the order of from and to.
// We determine the looping mode based on the order of from and to.
var mode = from.rowIndex > to.rowIndex ? 'previousSibling' : 'nextSibling';
// Traverse through the sibling nodes.
+6
View File
@@ -134,6 +134,8 @@ Drupal.verticalTab.prototype = {
tabShow: function () {
// Display the tab.
this.item.show();
// Show the vertical tabs.
this.item.closest('.vertical-tabs').show();
// Update .first marker for items. We need recurse from parent to retain the
// actual DOM element order as jQuery implements sortOrder, but not as public
// method.
@@ -164,6 +166,10 @@ Drupal.verticalTab.prototype = {
if ($firstTab.length) {
$firstTab.data('verticalTab').focus();
}
// Hide the vertical tabs (if no tabs remain).
else {
this.item.closest('.vertical-tabs').hide();
}
return this;
}
};