Skip to content

Commit

Permalink
Merge pull request #3135 from projectblacklight/csrf-protection
Browse files Browse the repository at this point in the history
[7.x] Set the X-CSRF-Token header on ajax call
  • Loading branch information
corylown authored Jan 24, 2024
2 parents 50bfe10 + 22f3e1d commit 85ad4cf
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 34 deletions.
65 changes: 34 additions & 31 deletions app/assets/javascripts/blacklight/blacklight.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
"use strict";

var Blacklight = function () {
const Blacklight = function () {
var buffer = new Array();
return {
onLoad: function onLoad(func) {
onLoad: function (func) {
buffer.push(func);
},
activate: function activate() {
activate: function () {
for (var i = 0; i < buffer.length; i++) {
buffer[i].call();
}
},
listeners: function listeners() {
listeners: function () {
var listeners = [];
if (typeof Turbo !== 'undefined') {
listeners.push('turbo:load');
Expand Down Expand Up @@ -39,14 +39,22 @@ Blacklight.listeners().forEach(function (listener) {
});
});
Blacklight.onLoad(function () {
var elem = document.querySelector('.no-js');
const elem = document.querySelector('.no-js');

// The "no-js" class may already have been removed because this function is
// run on every turbo:load event, in that case, it won't find an element.
if (!elem) return;
elem.classList.remove('no-js');
elem.classList.add('js');
});
Blacklight.csrfToken = () => {
var _document$querySelect;
return (_document$querySelect = document.querySelector('meta[name=csrf-token]')) === null || _document$querySelect === void 0 ? void 0 : _document$querySelect.content;
};
Blacklight.csrfParam = () => {
var _document$querySelect2;
return (_document$querySelect2 = document.querySelector('meta[name=csrf-param]')) === null || _document$querySelect2 === void 0 ? void 0 : _document$querySelect2.content;
};
window.Blacklight = Blacklight;
/*global Bloodhound */

Expand Down Expand Up @@ -89,7 +97,7 @@ Blacklight.onLoad(function () {
$(Blacklight.doBookmarkToggleBehavior.selector).blCheckboxSubmit({
// cssClass is added to elements added, plus used for id base
cssClass: 'toggle-bookmark',
success: function success(checked, response) {
success: function (checked, response) {
if (response.bookmarks) {
$('[data-role=bookmark-counter]').text(response.bookmarks.count);
}
Expand All @@ -105,8 +113,8 @@ Blacklight.onLoad(function () {
// Button clicks should change focus. As of 10/3/19, Firefox for Mac and
// Safari both do not set focus to a button on button click.
// See https://zellwk.com/blog/inconsistent-button-behavior/ for background information
document.querySelectorAll('button.collapse-toggle').forEach(function (button) {
button.addEventListener('click', function () {
document.querySelectorAll('button.collapse-toggle').forEach(button => {
button.addEventListener('click', () => {
event.target.focus();
});
});
Expand Down Expand Up @@ -187,15 +195,18 @@ Blacklight.onLoad(function () {
checkbox.attr('disabled', 'disabled');
$.ajax({
url: form.attr('action'),
beforeSend: function (xhr) {
xhr.setRequestHeader('X-CSRF-Token', Blacklight.csrfToken());
},
dataType: 'json',
type: form.attr('method').toUpperCase(),
data: form.serialize(),
error: function error() {
error: function () {
label.removeAttr('disabled');
checkbox.removeAttr('disabled');
options.error.call();
},
success: function success(data, status, xhr) {
success: function (data, status, xhr) {
//if app isn't running at all, xhr annoyingly
//reports success with status 0.
if (xhr.status != 0) {
Expand All @@ -219,10 +230,10 @@ Blacklight.onLoad(function () {
$.fn.blCheckboxSubmit.defaults = {
//cssClass is added to elements added, plus used for id base
cssClass: 'blCheckboxSubmit',
error: function error() {
error: function () {
alert("Error");
},
success: function success() {} //callback
success: function () {} //callback
};
})(jQuery);
/*global Blacklight */
Expand All @@ -234,11 +245,11 @@ Blacklight.doResizeFacetLabelsAndCounts = function () {
return b.textContent.length - a.textContent.length;
}
document.querySelectorAll('.facet-values, .pivot-facet').forEach(function (elem) {
var nodes = elem.querySelectorAll('.facet-count');
const nodes = elem.querySelectorAll('.facet-count');
// TODO: when we drop ie11 support, this can become the spread operator:
var longest = Array.from(nodes).sort(longer)[0];
const longest = Array.from(nodes).sort(longer)[0];
if (longest && longest.textContent) {
var width = longest.textContent.length + 1 + 'ch';
const width = longest.textContent.length + 1 + 'ch';
elem.querySelector('.facet-count').style.width = width;
}
});
Expand Down Expand Up @@ -443,23 +454,15 @@ Blacklight.doSearchContextBehavior = function () {
console.warn("do_search_context_behavior is deprecated. Use doSearchContextBehavior instead.");
return Blacklight.do_search_context_behavior();
}
var elements = document.querySelectorAll('a[data-context-href]');
const elements = document.querySelectorAll('a[data-context-href]');
// Equivalent to Array.from(), but supports ie11
var nodes = Array.prototype.slice.call(elements);
const nodes = Array.prototype.slice.call(elements);
nodes.forEach(function (element) {
element.addEventListener('click', function (e) {
Blacklight.handleSearchContextMethod.call(e.currentTarget, e);
});
});
};
Blacklight.csrfToken = function () {
var _document$querySelect;
return (_document$querySelect = document.querySelector('meta[name=csrf-token]')) === null || _document$querySelect === void 0 ? void 0 : _document$querySelect.content;
};
Blacklight.csrfParam = function () {
var _document$querySelect2;
return (_document$querySelect2 = document.querySelector('meta[name=csrf-param]')) === null || _document$querySelect2 === void 0 ? void 0 : _document$querySelect2.content;
};

// this is the Rails.handleMethod with a couple adjustments, described inline:
// first, we're attaching this directly to the event handler, so we can check for meta-keys
Expand All @@ -471,14 +474,14 @@ Blacklight.handleSearchContextMethod = function (event) {
var link = this;

// instead of using the normal href, we need to use the context href instead
var href = link.getAttribute('data-context-href');
var target = link.getAttribute('target');
var csrfToken = Blacklight.csrfToken();
var csrfParam = Blacklight.csrfParam();
var form = document.createElement('form');
let href = link.getAttribute('data-context-href');
let target = link.getAttribute('target');
let csrfToken = Blacklight.csrfToken();
let csrfParam = Blacklight.csrfParam();
let form = document.createElement('form');
form.method = 'post';
form.action = href;
var formContent = "<input name=\"_method\" value=\"post\" type=\"hidden\" />\n <input name=\"redirect\" value=\"".concat(link.getAttribute('href'), "\" type=\"hidden\" />");
let formContent = "<input name=\"_method\" value=\"post\" type=\"hidden\" />\n <input name=\"redirect\" value=\"".concat(link.getAttribute('href'), "\" type=\"hidden\" />");

// check for meta keys.. if set, we should open in a new tab
if (event.metaKey || event.ctrlKey) {
Expand Down
1 change: 1 addition & 0 deletions app/javascript/blacklight/checkbox_submit.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@

$.ajax({
url: form.attr('action'),
beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRF-Token', Blacklight.csrfToken()) },
dataType: 'json',
type: form.attr('method').toUpperCase(),
data: form.serialize(),
Expand Down
3 changes: 3 additions & 0 deletions app/javascript/blacklight/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,7 @@ Blacklight.onLoad(function () {
elem.classList.add('js')
})

Blacklight.csrfToken = () => document.querySelector('meta[name=csrf-token]')?.content
Blacklight.csrfParam = () => document.querySelector('meta[name=csrf-param]')?.content

window.Blacklight = Blacklight
3 changes: 0 additions & 3 deletions app/javascript/blacklight/search_context.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ Blacklight.doSearchContextBehavior = function() {
})
};

Blacklight.csrfToken = () => document.querySelector('meta[name=csrf-token]')?.content
Blacklight.csrfParam = () => document.querySelector('meta[name=csrf-param]')?.content

// this is the Rails.handleMethod with a couple adjustments, described inline:
// first, we're attaching this directly to the event handler, so we can check for meta-keys
Blacklight.handleSearchContextMethod = function(event) {
Expand Down

0 comments on commit 85ad4cf

Please sign in to comment.