diff --git a/configure-aspen.py b/configure-aspen.py
index e27e2faa66..ae0799bc67 100644
--- a/configure-aspen.py
+++ b/configure-aspen.py
@@ -3,6 +3,7 @@
import gittip
import gittip.wireup
import gittip.authentication
+import gittip.csrf
gittip.wireup.canonical()
@@ -14,8 +15,10 @@
website.github_callback = os.environ['GITHUB_CALLBACK'].decode('ASCII')
website.hooks.inbound_early.register(gittip.canonize)
+website.hooks.inbound_early.register(gittip.csrf.inbound)
website.hooks.inbound_early.register(gittip.authentication.inbound)
website.hooks.outbound_late.register(gittip.authentication.outbound)
+website.hooks.outbound_late.register(gittip.csrf.outbound)
def add_stuff(request):
diff --git a/gittip/authentication.py b/gittip/authentication.py
index fa9f7ce618..6ab9315ce9 100644
--- a/gittip/authentication.py
+++ b/gittip/authentication.py
@@ -136,4 +136,4 @@ def outbound(response):
#cookie['domain']
cookie['path'] = '/'
cookie['expires'] = rfc822.formatdate(expires)
- #cookie['httponly'] = "Yes, please."
+ cookie['httponly'] = "Yes, please."
diff --git a/requirements.txt b/requirements.txt
index a935c6386d..39b1ae458a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-./vendor/aspen-0.18.25.tar.bz2
+./vendor/aspen-0.18.26.tar.bz2
./vendor/psycopg2-2.4.5.tar.gz
./vendor/simplejson-2.3.2.tar.gz
./vendor/certifi-0.0.8.tar.gz
diff --git a/templates/base.html b/templates/base.html
index 2b99cd4284..f4ec782270 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -8,6 +8,7 @@
+
{% block heading %}
diff --git a/vendor/aspen-0.18.25.tar.bz2 b/vendor/aspen-0.18.25.tar.bz2
deleted file mode 100644
index 4958b7b761..0000000000
Binary files a/vendor/aspen-0.18.25.tar.bz2 and /dev/null differ
diff --git a/vendor/aspen-0.18.26.tar.bz2 b/vendor/aspen-0.18.26.tar.bz2
new file mode 100644
index 0000000000..1e883fb370
Binary files /dev/null and b/vendor/aspen-0.18.26.tar.bz2 differ
diff --git a/www/%participant_id/tip.json b/www/%participant_id/tip.json
index 46ee710c2b..6c5847221b 100644
--- a/www/%participant_id/tip.json
+++ b/www/%participant_id/tip.json
@@ -9,7 +9,6 @@ from gittip.networks import github
# ========================================================================== ^L
-
out = {}
if not user.ANON:
@@ -36,7 +35,7 @@ if not user.ANON:
# =====================
# Insert instead of update. The analytics may be interesting some day.
- if POST and 'amount' in body and body.get('csrf') == user.session_token:
+ if POST and 'amount' in body:
try:
amount = decimal.Decimal(body['amount'])
diff --git a/www/assets/%version/gittip.js b/www/assets/%version/gittip.js
index 3d8ce97503..6de62d0a2a 100644
--- a/www/assets/%version/gittip.js
+++ b/www/assets/%version/gittip.js
@@ -136,7 +136,6 @@ Gittip.submitForm = function(url, data, success, error)
console.log("failed", xhr, foo, bar);
}
- data.csrf = Gittip.getCookie('session');
jQuery.ajax({ url: url
, type: "GET"
, data: data
@@ -309,17 +308,45 @@ Gittip.initPayment = function(stripe_publishable_key, participantId)
});
};
-Gittip.getCookie = function(name)
-{ // http://www.quirksmode.org/js/cookies.html
- var nameEQ = name + "=";
- var ca = document.cookie.split(';');
- for(var i=0;i < ca.length;i++) {
- var c = ca[i];
- while (c.charAt(0)==' ') c = c.substring(1,c.length);
- if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
- }
- return null;
-}
+Gittip.initCSRF = function()
+{ // https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
+ jQuery(document).ajaxSend(function(event, xhr, settings) {
+ 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 sameOrigin(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));
+ }
+ function safeMethod(method) {
+ return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
+ }
+
+ if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
+ xhr.setRequestHeader("X-CSRF-TOKEN", getCookie('csrf_token'));
+ }
+ });
+};
Gittip.initTipButtons = function()
{
@@ -346,7 +373,7 @@ Gittip.initTipButtons = function()
select(this, amount);
jQuery.ajax(
{ url: '/' + tippee + '/tip.json'
- , data: {amount: amount, csrf: Gittip.getCookie('session')}
+ , data: {amount: amount}
, type: "POST"
, error: function(x,y,z) {
select(cur); console.log(x,y,z);