From d8321161de083b1c9504811e4efdd19bef44d800 Mon Sep 17 00:00:00 2001 From: Lova ANDRIARIMALALA <43842786+Xpirix@users.noreply.github.com> Date: Mon, 11 Dec 2023 20:35:39 +0300 Subject: [PATCH] List tokens for a specific plugin --- qgis-app/plugins/decorators.py | 32 ++--- .../plugins/outstandingtoken_list.html | 116 ++++++++++++++++++ .../plugins/token_delete_confirm.html | 9 ++ .../plugins/token_permission_deny.html | 4 + qgis-app/plugins/urls.py | 9 +- qgis-app/plugins/views.py | 67 +++++++--- qgis-app/settings.py | 3 + qgis-app/settings_docker.py | 1 + 8 files changed, 204 insertions(+), 37 deletions(-) create mode 100644 qgis-app/plugins/templates/plugins/outstandingtoken_list.html create mode 100644 qgis-app/plugins/templates/plugins/token_delete_confirm.html create mode 100644 qgis-app/plugins/templates/plugins/token_permission_deny.html diff --git a/qgis-app/plugins/decorators.py b/qgis-app/plugins/decorators.py index bdb496a4..d8e838f7 100644 --- a/qgis-app/plugins/decorators.py +++ b/qgis-app/plugins/decorators.py @@ -6,25 +6,25 @@ def has_valid_token(function): @wraps(function) def wrap(request, *args, **kwargs): - auth_token = request.META.get("HTTP_AUTHORIZATION") - package_name = kwargs.get('package_name') - if request.user.is_authenticated or not str(auth_token).startswith('Bearer'): - return function(request, *args, **kwargs) + auth_token = request.META.get("HTTP_AUTHORIZATION") + package_name = kwargs.get('package_name') + if request.user.is_authenticated or not str(auth_token).startswith('Bearer'): + return function(request, *args, **kwargs) - # Validate JWT token - authentication = JWTAuthentication() - validated_token = authentication.get_validated_token(auth_token[7:]) + # Validate JWT token + authentication = JWTAuthentication() + validated_token = authentication.get_validated_token(auth_token[7:]) - user = authentication.get_user(validated_token) - plugin_id = validated_token.payload.get('plugin_id') - if not plugin_id or not user: - return HttpResponseForbidden("Invalid token") - request.user = user + user = authentication.get_user(validated_token) + plugin_id = validated_token.payload.get('plugin_id') + if not plugin_id or not user: + return HttpResponseForbidden("Invalid token") + request.user = user - plugin = Plugin.objects.get(pk=plugin_id) - if not plugin or plugin.package_name != package_name: - return HttpResponseForbidden("Invalid token") + plugin = Plugin.objects.get(pk=plugin_id) + if not plugin or plugin.package_name != package_name: + return HttpResponseForbidden("Invalid token") - return function(request, *args, **kwargs) + return function(request, *args, **kwargs) return wrap diff --git a/qgis-app/plugins/templates/plugins/outstandingtoken_list.html b/qgis-app/plugins/templates/plugins/outstandingtoken_list.html new file mode 100644 index 00000000..59ab3a39 --- /dev/null +++ b/qgis-app/plugins/templates/plugins/outstandingtoken_list.html @@ -0,0 +1,116 @@ +{% extends 'plugins/plugin_base.html' %}{% load i18n %} +{% load local_timezone %} +{% block content %} +

{% trans "Tokens for" %} {{ plugin.name }}

+
+ + + + + + + + + + + + {% for token in object_list %} + + + + + + + + {% endfor %} + +
{% trans "User" %}{% trans "Token" %}{% trans "Created at" %}{% trans "Expires at" %}{% trans "Manage" %}
{{ token.user }} +
+ + {{ token.token }} + +
+
{{ token.created_at|local_timezone }}{{ token.expires_at|local_timezone }} +
+ +
+   + + +
+
+{% endblock %} + +{% block extracss %} +{{ block.super }} + +{% endblock %} + +{% block extrajs %} + +{% endblock %} \ No newline at end of file diff --git a/qgis-app/plugins/templates/plugins/token_delete_confirm.html b/qgis-app/plugins/templates/plugins/token_delete_confirm.html new file mode 100644 index 00000000..3cebe239 --- /dev/null +++ b/qgis-app/plugins/templates/plugins/token_delete_confirm.html @@ -0,0 +1,9 @@ +{% extends 'plugins/plugin_base.html' %}{% load i18n %} +{% block content %} +

Delete token of "{{ username }}"

+
{% csrf_token %} +

{% trans "You asked to delete a token.
The token will be permanently deleted and this action cannot be undone.
Please confirm." %}

+

{% trans "Cancel" %}

+
+ +{% endblock %} diff --git a/qgis-app/plugins/templates/plugins/token_permission_deny.html b/qgis-app/plugins/templates/plugins/token_permission_deny.html new file mode 100644 index 00000000..7850ee82 --- /dev/null +++ b/qgis-app/plugins/templates/plugins/token_permission_deny.html @@ -0,0 +1,4 @@ +{% extends 'plugins/plugin_base.html' %}{% load i18n %} +{% block content %} +
{% trans "You cannot see tokens for this plugin." %}
+{% endblock %} diff --git a/qgis-app/plugins/urls.py b/qgis-app/plugins/urls.py index 6b0c3111..2f41e327 100644 --- a/qgis-app/plugins/urls.py +++ b/qgis-app/plugins/urls.py @@ -49,10 +49,15 @@ ), url( r"^(?P[A-Za-z][A-Za-z0-9-_]+)/token/$", - plugin_token, - {}, + PluginTokenListView.as_view(), name="plugin_token", ), + url( + r"^(?P[A-Za-z][A-Za-z0-9-_]+)/token/(?P[^\/]+)/delete$", + token_delete, + {}, + name="token_delete", + ), url( r"^(?P[A-Za-z][A-Za-z0-9-_]+)/set_featured/$", plugin_set_featured, diff --git a/qgis-app/plugins/views.py b/qgis-app/plugins/views.py index a502758f..0143bcd1 100644 --- a/qgis-app/plugins/views.py +++ b/qgis-app/plugins/views.py @@ -34,6 +34,9 @@ from plugins.models import Plugin, PluginVersion, PluginVersionDownload, vjust from plugins.validator import PLUGIN_REQUIRED_METADATA +from rest_framework_simplejwt.token_blacklist.models import OutstandingToken, BlacklistedToken +from rest_framework_simplejwt.tokens import RefreshToken + try: from urllib import unquote, urlencode @@ -594,29 +597,55 @@ def plugin_update(request, package_name): {"form": form, "form_title": _("Edit plugin"), "plugin": plugin}, ) -from rest_framework_simplejwt.tokens import RefreshToken -@login_required -def plugin_token(request, package_name): + +class PluginTokenListView(ListView): """ - Plugin token management + Plugin token list """ + model = OutstandingToken + queryset = OutstandingToken.objects.all() + template_name = "plugins/outstandingtoken_list.html" + + @method_decorator(ensure_csrf_cookie) + def dispatch(self, *args, **kwargs): + return super(PluginTokenListView, self).dispatch(*args, **kwargs) + + def get_context_data(self, **kwargs): + package_name = self.kwargs.get('package_name') + plugin = get_object_or_404(Plugin, package_name=package_name) + if not check_plugin_access(self.request.user, plugin): + context = {} + self.template_name = "plugins/token_permission_deny.html" + return context + context = super(PluginTokenListView, self).get_context_data(**kwargs) + context.update( + { + "plugin": plugin + } + ) + return context + +@login_required +def token_delete(request, package_name, token_id): plugin = get_object_or_404(Plugin, package_name=package_name) - user = request.user - if not check_plugin_access(user, plugin): - return render(request, "plugins/plugin_permission_deny.html", {}) - - refresh = RefreshToken.for_user(user) - refresh['plugin_id'] = plugin.pk - - token = { - 'refresh': str(refresh), - 'access': str(refresh.access_token) - } - - print(token, '#############') - - return render(request, "plugins/plugin_permission_deny.html", {}) + outstanting_token = get_object_or_404(OutstandingToken, pk=token_id) + token = RefreshToken(outstanting_token.token) + if not check_plugin_access(request.user, plugin): + return render(request, "plugins/version_permission_deny.html", {}) + if "delete_confirm" in request.POST: + token.blacklist() + + msg = _("The token has been successfully deleted.") + messages.success(request, msg, fail_silently=True) + return HttpResponseRedirect( + reverse("plugin_token", args=(plugin.package_name,)) + ) + return render( + request, + "plugins/token_delete_confirm.html", + {"plugin": plugin, "username": outstanting_token.user}, + ) class PluginsList(ListView): diff --git a/qgis-app/settings.py b/qgis-app/settings.py index 54d76a4a..06a4a6b2 100644 --- a/qgis-app/settings.py +++ b/qgis-app/settings.py @@ -148,6 +148,9 @@ "leaflet", "bootstrapform", "rest_framework", + 'rest_framework.authtoken', + 'rest_framework_simplejwt', + 'rest_framework_simplejwt.token_blacklist', "rest_framework_gis", "preferences", # styles: diff --git a/qgis-app/settings_docker.py b/qgis-app/settings_docker.py index 86f44c6c..27742223 100644 --- a/qgis-app/settings_docker.py +++ b/qgis-app/settings_docker.py @@ -66,6 +66,7 @@ "rest_framework", 'rest_framework.authtoken', 'rest_framework_simplejwt', + 'rest_framework_simplejwt.token_blacklist', "sorl_thumbnail_serializer", # serialize image "drf_multiple_model", "drf_yasg",