@@ -40,6 +40,7 @@ class ApiError(Enum):
4040 INPUT_ERROR = 3
4141 UNAUTHORIZED = 4
4242 WRONG_SCHEME = 5
43+ BAD_REQUEST = 6
4344
4445
4546def _error (error : ApiError , msg : str ) -> JsonResponse :
@@ -66,30 +67,40 @@ def get_client_ip(request) -> str:
6667 return ip
6768
6869
69- def ensure_https_in_ops (fn ):
70+ # Checkers
71+ def request_checker (checker , error_msg ):
7072 """
71- Ensure that the view is called via an HTTPS request and return a JSON error
72- payload if not.
73+ Generic sanity check decorator on views.
7374
74- If DEBUG = True, it has no effect.
75+ It accepts two parameters:
76+ `checker`: a function that accepts a request and returns True if valid
77+ `error_msg`: what to return as error message if request is invalid
78+
79+ In case of invalid requests, it returns a BAD_REQUEST error.
7580 """
76- @wraps (fn )
77- def wrapper (request , * args , ** kwargs ):
78- if not DEBUG and not request .is_secure ():
79- return _error (ApiError .WRONG_SCHEME , 'please use HTTPS' )
80- return fn (request , * args , ** kwargs )
81- return wrapper
81+ def decorator (fn ):
82+ @wraps (fn )
83+ def wrapper (request , * args , ** kwargs ):
84+ if not checker (request ):
85+ return _error (ApiError .BAD_REQUEST , error_msg )
86+ return fn (request , * args , ** kwargs )
87+ return wrapper
88+ return decorator
89+
90+
91+ # Ensure that the view is called via an HTTPS request and return a JSON error
92+ # payload if not. If DEBUG = True, it has no effect.
93+ ensure_https_in_ops = request_checker (
94+ lambda r : DEBUG or r .is_secure (), 'please user HTTPS'
95+ )
8296
97+ # We use this instead of the bult-in decorator to return a JSON error
98+ # payload instead of a simple 405.
99+ ensure_post = request_checker (lambda r : r .method == 'POST' , 'please use POST' )
83100
84- def ensure_post (fn ):
85- # We use this instead of the bult-in decorator to return a JSON error
86- # payload instead of a simple 405.
87- @wraps (fn )
88- def wrapper (request , * args , ** kwargs ):
89- if request .method != 'POST' :
90- return _error (ApiError .WRONG_SCHEME , 'please use POST' )
91- return fn (request , * args , ** kwargs )
92- return wrapper
101+ ensure_json_content_type = request_checker (
102+ lambda r : r .content_type == 'application/json' , 'please send JSON'
103+ )
93104
94105
95106def restrict_client_ip_to_allowed_list (fn ):
@@ -107,6 +118,7 @@ def wrapper(request, *args, **kwargs):
107118@csrf_exempt
108119@ensure_post
109120@ensure_https_in_ops
121+ @ensure_json_content_type
110122@restrict_client_ip_to_allowed_list
111123def isauth (request ):
112124 """
0 commit comments