Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Add a decorator to put API user in request #1278 #1279

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 11 additions & 33 deletions signbank/api_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
from django.contrib.auth.models import Group, User
from signbank.zip_interface import *

from signbank.api_token import put_api_user_in_request


def api_fields(dataset, language_code='en', advanced=False):
activate(language_code)
Expand Down Expand Up @@ -84,26 +86,14 @@ def api_fields(dataset, language_code='en', advanced=False):
return api_fields_2023


@put_api_user_in_request
def get_fields_data_json(request, datasetid):

results = dict()
auth_token_request = request.headers.get('Authorization', '')
interface_language_code = request.headers.get('Accept-Language', 'en')
if interface_language_code not in settings.MODELTRANSLATION_LANGUAGES:
interface_language_code = 'en'
activate(interface_language_code)
if auth_token_request:
auth_token = auth_token_request.split('Bearer ')[-1]
hashed_token = hash_token(auth_token)
signbank_token = SignbankAPIToken.objects.filter(api_token=hashed_token).first()
if not signbank_token:
results['errors'] = [gettext("Your Authorization Token does not match anything.")]
return JsonResponse(results)
username = signbank_token.signbank_user.username
user = User.objects.get(username=username)
else:
user = request.user
interface_language_code = get_interface_language_api(request, user)
if request.user.is_authenticated:
interface_language_code = get_interface_language_api(request, request.user)

sequence_of_digits = True
for i in datasetid:
Expand All @@ -120,7 +110,7 @@ def get_fields_data_json(request, datasetid):
# ignore the database in the url if necessary
dataset = Dataset.objects.get(id=settings.DEFAULT_DATASET_PK)

if user.has_perm('dictionary.change_gloss'):
if request.user.has_perm('dictionary.change_gloss'):
api_fields_2023 = api_fields(dataset, interface_language_code, advanced=True)
else:
api_fields_2023 = api_fields(dataset, interface_language_code, advanced=False)
Expand All @@ -130,26 +120,14 @@ def get_fields_data_json(request, datasetid):
return JsonResponse(result)


@put_api_user_in_request
def get_gloss_data_json(request, datasetid, glossid):

results = dict()
auth_token_request = request.headers.get('Authorization', '')
interface_language_code = request.headers.get('Accept-Language', 'en')
if interface_language_code not in settings.MODELTRANSLATION_LANGUAGES:
interface_language_code = 'en'
activate(interface_language_code)
if auth_token_request:
auth_token = auth_token_request.split('Bearer ')[-1]
hashed_token = hash_token(auth_token)
signbank_token = SignbankAPIToken.objects.filter(api_token=hashed_token).first()
if not signbank_token:
results['errors'] = [gettext("Your Authorization Token does not match anything.")]
return JsonResponse(results)
username = signbank_token.signbank_user.username
user = User.objects.get(username=username)
else:
user = request.user
interface_language_code = get_interface_language_api(request, user)
if request.user.is_authenticated:
interface_language_code = get_interface_language_api(request, request.user)

sequence_of_digits = True
for i in datasetid:
Expand All @@ -162,7 +140,7 @@ def get_gloss_data_json(request, datasetid, glossid):

dataset_id = int(datasetid)
dataset = Dataset.objects.filter(id=dataset_id).first()
if not dataset or not user.is_authenticated:
if not dataset or not request.user.is_authenticated:
# ignore the dataset in the url if necessary
dataset = Dataset.objects.get(id=settings.DEFAULT_DATASET_PK)

Expand All @@ -181,7 +159,7 @@ def get_gloss_data_json(request, datasetid, glossid):
if not gloss:
return JsonResponse({})

if user.has_perm('dictionary.change_gloss'):
if request.user.has_perm('dictionary.change_gloss'):
api_fields_2023 = api_fields(dataset, interface_language_code, advanced=True)
else:
api_fields_2023 = api_fields(dataset, interface_language_code, advanced=False)
Expand Down
28 changes: 28 additions & 0 deletions signbank/api_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
import secrets
import string

from django.http import HttpRequest

from signbank.dictionary.models import SignbankAPIToken


def generate_auth_token(length=16):
"""Generate a random authentication token."""
Expand All @@ -16,3 +20,27 @@ def hash_token(token):
return hash_object.hexdigest()


def get_api_user(request):
"""Return a user based if there is an API token in the request, else None"""
auth_token_request = request.headers.get('Authorization', '')
if not auth_token_request:
return None

auth_token = auth_token_request.removeprefix('Bearer ')
if not auth_token:
return None

hashed_token = hash_token(auth_token)
signbank_token = SignbankAPIToken.objects.filter(api_token=hashed_token).first()
return signbank_token.signbank_user if signbank_token else None


def put_api_user_in_request(func):
"""A decorator to replace the request.user with the user found by checking an API token"""
def wrapper(*args, **kwargs):
if isinstance(args[0], HttpRequest):
request = args[0]
if api_user := get_api_user(request):
request.user = api_user
return func(*args, **kwargs)
return wrapper
3 changes: 3 additions & 0 deletions signbank/dictionary/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
from django.utils.translation import gettext_lazy as _, activate
from signbank.abstract_machine import get_interface_language_api

from signbank.api_token import put_api_user_in_request


def login_required_config(f):
"""like @login_required if the ALWAYS_REQUIRE_LOGIN setting is True"""
Expand Down Expand Up @@ -2308,6 +2310,7 @@ def package(request):
return response


@put_api_user_in_request
def info(request):
import guardian
user_datasets = guardian.shortcuts.get_objects_for_user(request.user, 'change_dataset', Dataset)
Expand Down