1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-12-10 13:47:47 +01:00

Compare commits

...

6 Commits

Author SHA1 Message Date
Alexis Mercier des Rochettes
5d41a13323 fix: prevent linters from bitching (again) 2025-12-10 00:12:36 +01:00
Alexis Mercier des Rochettes
245a989042 fix: use note name instead of username 2025-12-09 23:37:03 +01:00
Alexis Mercier des Rochettes
b1a90e31f4 fix: prevent linters from bitching 2025-12-09 23:26:30 +01:00
Alexis Mercier des Rochettes
23fe15d982 feat: qrcode data checker 2025-12-09 23:02:09 +01:00
Alexis Mercier des Rochettes
f79961c2f5 feat: distribute qrcode image over api/me/qrcode 2025-12-09 22:25:51 +01:00
Alexis Mercier des Rochettes
c333709334 feat: add requirements to requirements.txt 2025-12-09 20:41:38 +01:00
5 changed files with 51 additions and 7 deletions

View File

@@ -89,3 +89,11 @@ class OAuthSerializer(serializers.ModelSerializer):
'note', 'note',
'memberships', 'memberships',
) )
class QRCodeCheckSerializer(serializers.Serializer):
data = serializers.CharField(
label="Données du QR Code",
help_text="Le contenu brut lu depuis le QR Code (Username + Token)",
required=True
)

View File

@@ -3,17 +3,18 @@
from django.conf import settings from django.conf import settings
from django.conf.urls import include from django.conf.urls import include
from django.urls import re_path from django.urls import re_path, path
from rest_framework import routers from rest_framework import routers
from .views import UserInformationView from .views import UserInformationView
from .viewsets import ContentTypeViewSet, UserViewSet from .viewsets import ContentTypeViewSet, UserViewSet, QRCodeVerificationViewSet
# Routers provide an easy way of automatically determining the URL conf. # Routers provide an easy way of automatically determining the URL conf.
# Register each app API router and user viewset # Register each app API router and user viewset
router = routers.DefaultRouter() router = routers.DefaultRouter()
router.register('models', ContentTypeViewSet) router.register('models', ContentTypeViewSet)
router.register('user', UserViewSet) router.register('user', UserViewSet)
router.register('check_qrcode', QRCodeVerificationViewSet, basename='check_qrcode')
if "activity" in settings.INSTALLED_APPS: if "activity" in settings.INSTALLED_APPS:
from activity.api.urls import register_activity_urls from activity.api.urls import register_activity_urls
@@ -61,6 +62,7 @@ app_name = 'api'
# Additionally, we include login URLs for the browsable API. # Additionally, we include login URLs for the browsable API.
urlpatterns = [ urlpatterns = [
re_path('^', include(router.urls)), re_path('^', include(router.urls)),
re_path('^me/', UserInformationView.as_view()), path('me/', UserInformationView.as_view({'get': 'retrieve'})),
path('me/qrcode/', UserInformationView.as_view({'get': 'qrcode'})),
re_path('^api-auth/', include('rest_framework.urls', namespace='rest_framework')), re_path('^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
] ]

View File

@@ -1,13 +1,19 @@
# Copyright (C) 2018-2025 by BDE ENS Paris-Saclay # Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import base64
import os
from io import BytesIO
import qrcode
import pyotp
from django.contrib.auth.models import User from django.contrib.auth.models import User
from rest_framework.generics import RetrieveAPIView from django.http.response import HttpResponse
from rest_framework import viewsets, mixins
from .serializers import OAuthSerializer from .serializers import OAuthSerializer
class UserInformationView(RetrieveAPIView): class UserInformationView(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
""" """
These fields are give to OAuth authenticators. These fields are give to OAuth authenticators.
""" """
@@ -18,3 +24,11 @@ class UserInformationView(RetrieveAPIView):
def get_object(self): def get_object(self):
return self.request.user return self.request.user
def qrcode(self, request, *args, **kwargs):
secret = base64.b32encode(os.getenv("DJANGO_SECRET_KEY").encode())
qr_img = qrcode.make(f"{str(request.user.note)}{pyotp.TOTP(secret, interval=30).now()}")
buffer = BytesIO()
qr_img.save(buffer, format="PNG")
buffer.seek(0)
return HttpResponse(buffer, content_type="image/png")

View File

@@ -2,18 +2,22 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import re import re
import base64
import os
import pyotp
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
from django.db.models import Q from django.db.models import Q
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet, GenericViewSet
from rest_framework.response import Response
from permission.backends import PermissionBackend from permission.backends import PermissionBackend
from note.models import Alias from note.models import Alias
from .filters import RegexSafeSearchFilter from .filters import RegexSafeSearchFilter
from .serializers import UserSerializer, ContentTypeSerializer from .serializers import UserSerializer, ContentTypeSerializer, QRCodeCheckSerializer
def is_regex(pattern): def is_regex(pattern):
@@ -124,3 +128,17 @@ class ContentTypeViewSet(ReadOnlyModelViewSet):
filter_backends = [DjangoFilterBackend, RegexSafeSearchFilter] filter_backends = [DjangoFilterBackend, RegexSafeSearchFilter]
filterset_fields = ['id', 'app_label', 'model', ] filterset_fields = ['id', 'app_label', 'model', ]
search_fields = ['$app_label', '$model', ] search_fields = ['$app_label', '$model', ]
class QRCodeVerificationViewSet(GenericViewSet):
serializer_class = QRCodeCheckSerializer
queryset = User.objects.none()
def get_view_name(self):
return "Vérification QR Code"
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
secret = base64.b32encode(os.getenv("DJANGO_SECRET_KEY").encode())
return Response({'valid': pyotp.TOTP(secret, interval=30).verify(serializer.validated_data['data'][-6:])})

View File

@@ -20,3 +20,5 @@ python-memcached~=1.62
phonenumbers~=9.0.8 phonenumbers~=9.0.8
tablib~=3.8.0 tablib~=3.8.0
Pillow>=11.3.0 Pillow>=11.3.0
pyotp~=2.9.0
qrcode~=8.2