refactor: Implement require_api_key with functools.wraps
The @decorator mechanism does not seem to work with @method_decorator in Django 4.0, have not tracked down why.
This commit is contained in:
parent
223c679942
commit
8cf609bfa9
|
@ -5,6 +5,7 @@
|
|||
import datetime
|
||||
|
||||
from decorator import decorator, decorate
|
||||
from functools import wraps
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import login
|
||||
|
@ -39,52 +40,54 @@ def person_required(f, request, *args, **kwargs):
|
|||
return render(request, 'registration/missing_person.html')
|
||||
return f(request, *args, **kwargs)
|
||||
|
||||
@decorator
|
||||
def require_api_key(f, request, *args, **kwargs):
|
||||
|
||||
def err(code, text):
|
||||
return HttpResponse(text, status=code, content_type='text/plain')
|
||||
# Check method and get hash
|
||||
if request.method == 'POST':
|
||||
hash = request.POST.get('apikey')
|
||||
elif request.method == 'GET':
|
||||
hash = request.GET.get('apikey')
|
||||
else:
|
||||
return err(405, "Method not allowed")
|
||||
if not hash:
|
||||
return err(400, "Missing apikey parameter")
|
||||
# Check hash
|
||||
key = PersonalApiKey.validate_key(force_bytes(hash))
|
||||
if not key:
|
||||
return err(403, "Invalid apikey")
|
||||
# Check endpoint
|
||||
urlpath = request.META.get('PATH_INFO')
|
||||
if not (urlpath and urlpath == key.endpoint):
|
||||
return err(400, "Apikey endpoint mismatch")
|
||||
# Check time since regular login
|
||||
person = key.person
|
||||
last_login = person.user.last_login
|
||||
if not person.user.is_staff:
|
||||
time_limit = (timezone.now() - datetime.timedelta(days=settings.UTILS_APIKEY_GUI_LOGIN_LIMIT_DAYS))
|
||||
if last_login == None or last_login < time_limit:
|
||||
return err(400, "Too long since last regular login")
|
||||
# Log in
|
||||
login(request, person.user)
|
||||
# restore the user.last_login field, so it reflects only gui logins
|
||||
person.user.last_login = last_login
|
||||
person.user.save()
|
||||
# Update stats
|
||||
key.count += 1
|
||||
key.latest = timezone.now()
|
||||
key.save()
|
||||
PersonApiKeyEvent.objects.create(person=person, type='apikey_login', key=key, desc="Logged in with key ID %s, endpoint %s" % (key.id, key.endpoint))
|
||||
# Execute decorated function
|
||||
try:
|
||||
ret = f(request, *args, **kwargs)
|
||||
except AttributeError as e:
|
||||
log.log("Bad API call: args: %s, kwargs: %s, exception: %s" % (args, kwargs, e))
|
||||
return err(400, "Bad or missing parameters")
|
||||
return ret
|
||||
def require_api_key(f):
|
||||
@wraps(f)
|
||||
def _wrapper(request, *args, **kwargs):
|
||||
def err(code, text):
|
||||
return HttpResponse(text, status=code, content_type='text/plain')
|
||||
# Check method and get hash
|
||||
if request.method == 'POST':
|
||||
hash = request.POST.get('apikey')
|
||||
elif request.method == 'GET':
|
||||
hash = request.GET.get('apikey')
|
||||
else:
|
||||
return err(405, "Method not allowed")
|
||||
if not hash:
|
||||
return err(400, "Missing apikey parameter")
|
||||
# Check hash
|
||||
key = PersonalApiKey.validate_key(force_bytes(hash))
|
||||
if not key:
|
||||
return err(403, "Invalid apikey")
|
||||
# Check endpoint
|
||||
urlpath = request.META.get('PATH_INFO')
|
||||
if not (urlpath and urlpath == key.endpoint):
|
||||
return err(400, "Apikey endpoint mismatch")
|
||||
# Check time since regular login
|
||||
person = key.person
|
||||
last_login = person.user.last_login
|
||||
if not person.user.is_staff:
|
||||
time_limit = (timezone.now() - datetime.timedelta(days=settings.UTILS_APIKEY_GUI_LOGIN_LIMIT_DAYS))
|
||||
if last_login == None or last_login < time_limit:
|
||||
return err(400, "Too long since last regular login")
|
||||
# Log in
|
||||
login(request, person.user)
|
||||
# restore the user.last_login field, so it reflects only gui logins
|
||||
person.user.last_login = last_login
|
||||
person.user.save()
|
||||
# Update stats
|
||||
key.count += 1
|
||||
key.latest = timezone.now()
|
||||
key.save()
|
||||
PersonApiKeyEvent.objects.create(person=person, type='apikey_login', key=key, desc="Logged in with key ID %s, endpoint %s" % (key.id, key.endpoint))
|
||||
# Execute decorated function
|
||||
try:
|
||||
ret = f(request, *args, **kwargs)
|
||||
except AttributeError as e:
|
||||
log.log("Bad API call: args: %s, kwargs: %s, exception: %s" % (args, kwargs, e))
|
||||
return err(400, "Bad or missing parameters")
|
||||
return ret
|
||||
return _wrapper
|
||||
|
||||
|
||||
def _memoize(func, self, *args, **kwargs):
|
||||
|
|
|
@ -11,7 +11,9 @@ from django.utils.encoding import force_str
|
|||
from django.views.generic import View
|
||||
|
||||
def url(regex, view, kwargs=None, name=None):
|
||||
if callable(view) and hasattr(view, '__name__'):
|
||||
if hasattr(view, "view_class"):
|
||||
view_name = "%s.%s" % (view.__module__, view.view_class.__name__)
|
||||
elif callable(view) and hasattr(view, '__name__'):
|
||||
view_name = "%s.%s" % (view.__module__, view.__name__)
|
||||
else:
|
||||
view_name = regex
|
||||
|
|
Loading…
Reference in a new issue