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 }}
+
+
+
+
+ {% trans "User" %} |
+ {% trans "Token" %} |
+ {% trans "Created at" %} |
+ {% trans "Expires at" %} |
+ {% trans "Manage" %} |
+
+
+
+ {% for token in object_list %}
+
+ {{ token.user }} |
+
+
+
+ {{ token.token }}
+
+
+ |
+ {{ token.created_at|local_timezone }} |
+ {{ token.expires_at|local_timezone }} |
+
+
+
+
+
+
+
+ |
+
+ {% endfor %}
+
+
+
+{% 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 }}"
+
+
+{% 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",