From 03aabca75e081890db5e769df87600dd9d27cadb Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Sat, 11 May 2013 14:50:27 +0200 Subject: [PATCH] Use DELETE method instead of GET. --- modoboa/admin/static/admin/js/admin.js | 7 +++- modoboa/admin/views.py | 3 ++ modoboa/static/js/confirmation.js | 4 ++- modoboa/static/js/csrf.js | 47 ++++++++++++++++++++++++++ modoboa/templates/nlayout.html | 1 + 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 modoboa/static/js/csrf.js diff --git a/modoboa/admin/static/admin/js/admin.js b/modoboa/admin/static/admin/js/admin.js index 1b337dc0e..3699c58da 100644 --- a/modoboa/admin/static/admin/js/admin.js +++ b/modoboa/admin/static/admin/js/admin.js @@ -46,7 +46,7 @@ Admin.prototype = { e.preventDefault(); }); if (data.page != this.navobj.getparam("page")) { - this.navobj.setparam("page", data.page).update(false, false); + this.navobj.setparam("page", data.page).update(false, true); } }, @@ -155,6 +155,7 @@ Domains.prototype = { $("a[name=deldomain]").confirm({ question: gettext("Delete this domain?"), + method: "DELETE", warning: warnmsg, checkboxes: deloptions, success_cb: $.proxy(this.reload_listing, this) @@ -281,19 +282,23 @@ Identities.prototype = { $("a[name=delaccount]").confirm({ question: gettext("Delete this account?"), + method: "DELETE", checkboxes: deloptions, success_cb: $.proxy(this.reload_listing, this) }); $("a[name=deldlist]").confirm({ question: gettext("Delete this list?"), + method: "DELETE", success_cb: $.proxy(this.reload_listing, this) }); $("a[name=delforward]").confirm({ question: gettext("Delete this forward?"), + method: "DELETE", success_cb: $.proxy(this.reload_listing, this) }); $("a[name=delalias]").confirm({ question: gettext("Delete this alias?"), + method: "DELETE", success_cb: $.proxy(this.reload_listing, this) }); }, diff --git a/modoboa/admin/views.py b/modoboa/admin/views.py index 8772cf4a4..1f8c29af8 100644 --- a/modoboa/admin/views.py +++ b/modoboa/admin/views.py @@ -8,6 +8,7 @@ from django.db.models import Q from django.shortcuts import render from django.template.loader import render_to_string from django.db import transaction, IntegrityError +from django.views.decorators.csrf import ensure_csrf_cookie import cStringIO import csv @@ -54,6 +55,7 @@ def _domains(request): @login_required +@ensure_csrf_cookie def domains(request, tplname="admin/domains.html"): if not request.user.has_perm("admin.view_domains"): if request.user.has_perm("admin.view_mailboxes"): @@ -356,6 +358,7 @@ def _identities(request): @login_required @user_passes_test(lambda u: u.has_perm("admin.add_user") or u.has_perm("admin.add_alias")) +@ensure_csrf_cookie def identities(request, tplname="admin/identities.html"): return render(request, tplname, { "selection": "identities", diff --git a/modoboa/static/js/confirmation.js b/modoboa/static/js/confirmation.js index 0e919e1ca..e360eba04 100644 --- a/modoboa/static/js/confirmation.js +++ b/modoboa/static/js/confirmation.js @@ -25,7 +25,7 @@ result = '
'; $.each(this.options.checkboxes, function(key, val) { result += ""; + result += val + ""; }); result += '
'; return result; @@ -88,6 +88,7 @@ $.ajax({ cache: false, + method: this.options.method, data: params, url: this.$element.attr('href'), complete: $.proxy(function(XMLHttpRequest, textStatus) { @@ -129,6 +130,7 @@ $.fn.confirm.defaults = { question: "", + method: "GET", warning: null, checkboxes: null }; diff --git a/modoboa/static/js/csrf.js b/modoboa/static/js/csrf.js new file mode 100644 index 000000000..9835b64ed --- /dev/null +++ b/modoboa/static/js/csrf.js @@ -0,0 +1,47 @@ +function getCookie(name) { + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; +} + +function csrfSafeMethod(method) { + // these HTTP methods do not require CSRF protection + return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); +} + +function sameOrigin(url) { + // test that a given url is a same-origin URL + // url could be relative or scheme relative or absolute + var host = document.location.host; // host + port + var protocol = document.location.protocol; + var sr_origin = '//' + host; + var origin = protocol + sr_origin; + // Allow absolute or scheme relative URLs to same origin + return (url == origin || url.slice(0, origin.length + 1) == origin + '/') || + (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') || + // or any other URL that isn't scheme relative or absolute i.e relative. + !(/^(\/\/|http:|https:).*/.test(url)); +} + +$.ajaxSetup({ + beforeSend: function(xhr, settings) { + var csrftoken = getCookie("csrftoken"); + + if (csrftoken && !csrfSafeMethod(settings.type) && sameOrigin(settings.url)) { + // Send the token to same-origin, relative URLs only. + // Send the token only if the method warrants CSRF protection + // Using the CSRFToken value acquired earlier + xhr.setRequestHeader("X-CSRFToken", csrftoken); + } + } +}); diff --git a/modoboa/templates/nlayout.html b/modoboa/templates/nlayout.html index 08ce58afc..6ca651935 100644 --- a/modoboa/templates/nlayout.html +++ b/modoboa/templates/nlayout.html @@ -13,6 +13,7 @@ {% if LANGUAGE_CODE != "en" %}{% endif %} +