Commit a4998508 authored by Einar Uvsløkk's avatar Einar Uvsløkk
Browse files

Move RememberMe implementation to users module

parent 43365a35
# Generated by Django 3.1 on 2021-04-14 18:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0009_auto_20210204_1055'),
]
operations = [
migrations.CreateModel(
name='RememberMe',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('remember_me', models.CharField(max_length=500)),
],
),
]
......@@ -71,3 +71,17 @@ class Offer(models.Model):
status = models.CharField(max_length=8, choices=STATUS_CHOICES, default=PENDING)
timestamp = models.DateTimeField(auto_now_add=True)
class RememberMe(models.Model):
"""Django model for an remember_me cookie used for remember me
functionality.
Attributes:
remember_me: Value of cookie used for remember me
"""
remember_me = models.CharField(max_length=500)
def __str__(self):
return self.remember_me
......@@ -5,6 +5,7 @@ from rest_framework import serializers
from users.models import AthleteFile
from users.models import Offer
from users.models import RememberMe
class UserSerializer(serializers.HyperlinkedModelSerializer):
......@@ -129,3 +130,18 @@ class OfferSerializer(serializers.HyperlinkedModelSerializer):
"status",
"timestamp",
]
class RememberMeSerializer(serializers.HyperlinkedModelSerializer):
"""Serializer for an RememberMe. Hyperlinks are used for relationships by
default.
Serialized fields: remember_me
Attributes:
remember_me: Value of cookie used for remember me functionality
"""
class Meta:
model = RememberMe
fields = ["remember_me"]
......@@ -22,4 +22,5 @@ urlpatterns = [
path("api/auth/", include("rest_framework.urls")),
path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
path("api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
path("api/remember_me/", views.RememberMe.as_view(), name="remember_me"),
]
import base64
import pickle
from collections import namedtuple
from django.contrib.auth import get_user_model
from django.core.exceptions import PermissionDenied
from django.core.signing import Signer
from django.db.models import Q
from rest_framework import generics
from rest_framework import mixins
......@@ -6,6 +12,8 @@ from rest_framework import permissions
from rest_framework.parsers import FormParser
from rest_framework.parsers import MultiPartParser
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
from users.models import AthleteFile
from users.models import Offer
......@@ -14,6 +22,7 @@ from users.permissions import IsCoach
from users.permissions import IsCurrentUser
from users.serializers import AthleteFileSerializer
from users.serializers import OfferSerializer
from users.serializers import RememberMeSerializer
from users.serializers import UserGetSerializer
from users.serializers import UserPutSerializer
from users.serializers import UserSerializer
......@@ -190,3 +199,48 @@ class AthleteFileDetail(
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
class RememberMe(
mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView,
):
serializer_class = RememberMeSerializer
def get(self, request):
if request.user.is_authenticated == False:
raise PermissionDenied
else:
return Response({"remember_me": self.rememberme()})
def post(self, request):
cookieObject = namedtuple("Cookies", request.COOKIES.keys())(
*request.COOKIES.values()
)
user = self.get_user(cookieObject)
refresh = RefreshToken.for_user(user)
return Response(
{
"refresh": str(refresh),
"access": str(refresh.access_token),
}
)
def get_user(self, cookieObject):
decode = base64.b64decode(cookieObject.remember_me)
user, sign = pickle.loads(decode)
if sign == self.sign_user(user):
return user
def rememberme(self):
creds = [self.request.user, self.sign_user(str(self.request.user))]
return base64.b64encode(pickle.dumps(creds))
def sign_user(self, username):
signer = Signer()
signed_user = signer.sign(username)
return signed_user
# Generated by Django 3.1 on 2021-04-14 18:50
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('workouts', '0003_rememberme'),
]
operations = [
migrations.DeleteModel(
name='RememberMe',
),
]
......@@ -150,20 +150,6 @@ class WorkoutFile(models.Model):
file = models.FileField(upload_to=workout_directory_path)
class RememberMe(models.Model):
"""Django model for an remember_me cookie used for remember me
functionality.
Attributes:
remember_me: Value of cookie used for remember me
"""
remember_me = models.CharField(max_length=500)
def __str__(self):
return self.remember_me
@dataclass
@functools.total_ordering
class HighScore:
......
......@@ -6,6 +6,7 @@ from rest_framework import parsers
class MultipartJsonParser(parsers.MultiPartParser):
"""Parser for serializing multipart data containing both files and JSON.
Thanks to https://stackoverflow.com/a/50514630
"""
......
......@@ -4,7 +4,6 @@ from rest_framework.serializers import HyperlinkedRelatedField
from workouts.models import Exercise
from workouts.models import ExerciseInstance
from workouts.models import RememberMe
from workouts.models import Workout
from workouts.models import WorkoutFile
......@@ -217,21 +216,6 @@ class ExerciseSerializer(serializers.HyperlinkedModelSerializer):
fields = ["url", "id", "name", "description", "unit", "instances"]
class RememberMeSerializer(serializers.HyperlinkedModelSerializer):
"""Serializer for an RememberMe. Hyperlinks are used for relationships by
default.
Serialized fields: remember_me
Attributes:
remember_me: Value of cookie used for remember me functionality
"""
class Meta:
model = RememberMe
fields = ["remember_me"]
class HighScoreSerializer(serializers.Serializer):
"""Serializer for a HighScore.
......
......@@ -39,6 +39,5 @@ urlpatterns = format_suffix_patterns(
views.WorkoutFileDetail.as_view(),
name="workoutfile-detail",
),
path("api/remember_me/", views.RememberMe.as_view(), name="remember_me"),
]
)
......@@ -2,13 +2,8 @@
These are mostly class-based views.
"""
import base64
import pickle
from collections import namedtuple
from operator import attrgetter
from django.core.exceptions import PermissionDenied
from django.core.signing import Signer
from django.db.models import Q
from rest_framework import filters
from rest_framework import generics
......@@ -18,7 +13,6 @@ from rest_framework.decorators import api_view
from rest_framework.parsers import JSONParser
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework_simplejwt.tokens import RefreshToken
from workouts.mixins import CreateListModelMixin
from workouts.models import Exercise
......@@ -37,7 +31,6 @@ from workouts.permissions import IsWorkoutPublic
from workouts.serializers import ExerciseInstanceSerializer
from workouts.serializers import ExerciseSerializer
from workouts.serializers import HighScoreSerializer
from workouts.serializers import RememberMeSerializer
from workouts.serializers import WorkoutFileSerializer
from workouts.serializers import WorkoutSerializer
......@@ -61,51 +54,6 @@ def api_root(request, format=None):
)
class RememberMe(
mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView,
):
serializer_class = RememberMeSerializer
def get(self, request):
if request.user.is_authenticated == False:
raise PermissionDenied
else:
return Response({"remember_me": self.rememberme()})
def post(self, request):
cookieObject = namedtuple("Cookies", request.COOKIES.keys())(
*request.COOKIES.values()
)
user = self.get_user(cookieObject)
refresh = RefreshToken.for_user(user)
return Response(
{
"refresh": str(refresh),
"access": str(refresh.access_token),
}
)
def get_user(self, cookieObject):
decode = base64.b64decode(cookieObject.remember_me)
user, sign = pickle.loads(decode)
if sign == self.sign_user(user):
return user
def rememberme(self):
creds = [self.request.user, self.sign_user(str(self.request.user))]
return base64.b64encode(pickle.dumps(creds))
def sign_user(self, username):
signer = Signer()
signed_user = signer.sign(username)
return signed_user
class WorkoutList(
mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView
):
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment