diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c089093..85be813 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,7 +4,7 @@ on: [push, pull_request] jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: fail-fast: false max-parallel: 5 diff --git a/knox/admin.py b/knox/admin.py index a045f7a..25e0138 100644 --- a/knox/admin.py +++ b/knox/admin.py @@ -1,10 +1,50 @@ -from django.contrib import admin +from django import forms +from django.contrib import admin, messages +from django.contrib.auth import get_user_model from knox import models +from knox.settings import CONSTANTS + + +class AuthTokenCreateForm(forms.ModelForm): + + def __init__(self, *args, **kwargs): + super(AuthTokenCreateForm, self).__init__(*args, **kwargs) + self.token = None + + class Meta: + model = models.AuthToken + fields = ['user', 'expiry'] + + def save(self, commit=True): + obj = super(AuthTokenCreateForm, self).save(commit=False) + digest, token = models.get_digest_token() + obj.digest = digest + obj.token_key = token[:CONSTANTS.TOKEN_KEY_LENGTH] + self.token = token + if commit: + obj.save() + obj.save_m2m() + return obj @admin.register(models.AuthToken) class AuthTokenAdmin(admin.ModelAdmin): + add_form = AuthTokenCreateForm list_display = ('digest', 'user', 'created', 'expiry',) + # We dont know how a custom User model looks like, but is must have a USERNAME_FIELD + search_fields = ['digest', 'token_key', 'user__'+get_user_model().USERNAME_FIELD] fields = () raw_id_fields = ('user',) + + def get_form(self, request, obj=None, **kwargs): + defaults = {} + if obj is None: + defaults['form'] = self.add_form + defaults.update(kwargs) + return super(AuthTokenAdmin, self).get_form(request, obj, **defaults) + + def save_model(self, request, obj, form, change): + if not change: + self.message_user(request, "TOKEN " + form.token, messages.INFO) + super(AuthTokenAdmin, self).save_model(request, obj, form, change) diff --git a/knox/models.py b/knox/models.py index 8b0a179..ad4860c 100644 --- a/knox/models.py +++ b/knox/models.py @@ -12,6 +12,18 @@ User = settings.AUTH_USER_MODEL +def get_expiry(expiry): + if expiry is not None: + expiry = timezone.now() + expiry + return expiry + + +def get_digest_token(prefix=knox_settings.TOKEN_PREFIX): + token = prefix + crypto.create_token_string() + digest = crypto.hash_token(token) + return digest, token + + class AuthTokenManager(models.Manager): def create( self, @@ -20,8 +32,8 @@ def create( prefix=knox_settings.TOKEN_PREFIX, **kwargs ): - token = prefix + crypto.create_token_string() - digest = crypto.hash_token(token) + + digest, token = get_digest_token(prefix) if expiry is not None: expiry = timezone.now() + expiry instance = super().create(