diff --git a/zerver/middleware.py b/zerver/middleware.py index 3c6a326a1f..9cfd47c569 100644 --- a/zerver/middleware.py +++ b/zerver/middleware.py @@ -9,6 +9,7 @@ from zerver.lib.cache import get_memcached_time, get_memcached_requests from zerver.lib.bugdown import get_bugdown_time, get_bugdown_requests from zerver.models import flush_per_request_caches from zerver.exceptions import RateLimited +from django.views.csrf import csrf_failure as html_csrf_failure import logging import time @@ -219,6 +220,21 @@ class JsonErrorHandler(object): return json_error(exception.to_json_error_msg()) return None +class TagRequests(object): + def process_view(self, request, view_func, args, kwargs): + self.process_request(request) + def process_request(self, request): + if request.path.startswith("/api/") or request.path.startswith("/json/"): + request.error_format = "JSON" + else: + request.error_format = "HTML" + +def csrf_failure(request, reason=""): + if request.error_format == "JSON": + return json_error("CSRF Error: %s" % (reason,), status=403) + else: + return html_csrf_failure(request, reason) + # Monkeypatch in time tracking to the Django non-debug cursor # Code comes from CursorDebugWrapper def wrapper_execute(self, action, sql, params=()): diff --git a/zproject/settings.py b/zproject/settings.py index 92379b5fd6..2aa849057e 100644 --- a/zproject/settings.py +++ b/zproject/settings.py @@ -131,6 +131,7 @@ if DEPLOYED: # the token from the DOM, which means malicious code could too. But hiding the # cookie will slow down some attackers. CSRF_COOKIE_PATH = '/;HttpOnly' +CSRF_FAILURE_VIEW = 'zerver.middleware.csrf_failure' # Base URL of the Tornado server # We set it to None when running backend tests or populate_db. @@ -154,6 +155,7 @@ if DEPLOYED: MIDDLEWARE_CLASSES = ( # Our logging middleware should be the first middleware item. + 'zerver.middleware.TagRequests', 'zerver.middleware.LogRequests', 'zerver.middleware.JsonErrorHandler', 'zerver.middleware.RateLimitMiddleware',