Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-django-rest-knox for 
openSUSE:Factory checked in at 2024-09-01 19:22:36
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-django-rest-knox (Old)
 and      /work/SRC/openSUSE:Factory/.python-django-rest-knox.new.2698 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-django-rest-knox"

Sun Sep  1 19:22:36 2024 rev:9 rq:1198089 version:5.0.1

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-django-rest-knox/python-django-rest-knox.changes
  2024-03-21 17:01:39.911128509 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-django-rest-knox.new.2698/python-django-rest-knox.changes
        2024-09-01 19:23:04.148049632 +0200
@@ -1,0 +2,28 @@
+Sat Aug 31 14:50:57 UTC 2024 - Dirk Müller <[email protected]>
+
+- update to 5.0.1:
+  * Fix migration: retrieve `TOKEN_MODEL` from `knox_settings`
+    instead of Django settings.
+  * Tokens created prior to this release will no longer work
+  * Fix migration reverse flow, enable migrate 0
+  * Various documentation fixes and improvements
+  * Drop `cryptography` in favor of hashlib
+  * Make custom AuthModel work
+  * Token prefix can be set in the setttings
+  * Drop support for Django 4.0
+  * Add support for Dango 4.2, 5.0 and Python 3.11 and 3.12
+  * Cleanup legacy Python 2.0 code
+  * Fix isort, flake8 usage for Python 3.10 in the test suite
+  * Update Github actions version
+  * Upgrade markdown dependency
+  * Get rid of the `six` library
+  * Add custom login / logout response support
+  * Join the jazzband organization
+  * Add pre-commit hooks
+  * Add tracking of tests code coverage
+  * Fix migrations when used in condition with a custom DB
+  * Improve typing
+  * Use `self.authenticate_header()` in `authenticate()` method
+    to get auth header prefix
+
+-------------------------------------------------------------------

Old:
----
  django-rest-knox-4.2.0.tar.gz

New:
----
  django-rest-knox-5.0.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-django-rest-knox.spec ++++++
--- /var/tmp/diff_new_pack.OrEUQg/_old  2024-09-01 19:23:04.612068630 +0200
+++ /var/tmp/diff_new_pack.OrEUQg/_new  2024-09-01 19:23:04.616068794 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-django-rest-knox
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -20,7 +20,7 @@
 %define skip_python2 1
 %{?sle15_python_module_pythons}
 Name:           python-django-rest-knox
-Version:        4.2.0
+Version:        5.0.1
 Release:        0
 Summary:        Authentication for Django REST framework
 License:        MIT

++++++ django-rest-knox-4.2.0.tar.gz -> django-rest-knox-5.0.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/.codecov.yml 
new/django-rest-knox-5.0.1/.codecov.yml
--- old/django-rest-knox-4.2.0/.codecov.yml     1970-01-01 01:00:00.000000000 
+0100
+++ new/django-rest-knox-5.0.1/.codecov.yml     2024-07-19 18:36:00.000000000 
+0200
@@ -0,0 +1,11 @@
+coverage:
+  status:
+    project:
+      default: false
+      tests:
+        paths: tests
+        informational: true
+      knox:
+        paths: knox
+        informational: true
+    patch: off
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/.coveragerc 
new/django-rest-knox-5.0.1/.coveragerc
--- old/django-rest-knox-4.2.0/.coveragerc      1970-01-01 01:00:00.000000000 
+0100
+++ new/django-rest-knox-5.0.1/.coveragerc      2024-07-19 18:36:00.000000000 
+0200
@@ -0,0 +1,5 @@
+[run]
+branch = True
+source = knox
+omit =
+    */migrations/*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-rest-knox-4.2.0/.github/workflows/gh-pages.yml 
new/django-rest-knox-5.0.1/.github/workflows/gh-pages.yml
--- old/django-rest-knox-4.2.0/.github/workflows/gh-pages.yml   1970-01-01 
01:00:00.000000000 +0100
+++ new/django-rest-knox-5.0.1/.github/workflows/gh-pages.yml   2024-07-19 
18:36:00.000000000 +0200
@@ -0,0 +1,34 @@
+name: Publish Docs to GitHub Pages
+
+permissions:
+  contents: write
+
+on:
+  push:
+    branches:
+      - develop
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v2
+
+      - name: Set up Python
+        uses: actions/setup-python@v2
+        with:
+          python-version: 3.x
+
+      - name: Install dependencies
+        run: pip install mkdocs-material
+
+      - name: Build docs
+        run: mkdocs build
+
+      - name: Deploy to GitHub Pages
+        uses: peaceiris/actions-gh-pages@v3
+        with:
+          personal_token: ${{ secrets.GITHUB_TOKEN }}
+          publish_dir: ./site
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/.github/workflows/test.yml 
new/django-rest-knox-5.0.1/.github/workflows/test.yml
--- old/django-rest-knox-4.2.0/.github/workflows/test.yml       2022-01-31 
16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/.github/workflows/test.yml       2024-07-19 
18:36:00.000000000 +0200
@@ -9,23 +9,23 @@
       fail-fast: false
       max-parallel: 5
       matrix:
-        python-version: ['3.6', '3.7', '3.8', '3.9', '3.10']
+        python-version: ['3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12']
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v4
 
     - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
         python-version: ${{ matrix.python-version }}
 
     - name: Get pip cache dir
       id: pip-cache
       run: |
-        echo "::set-output name=dir::$(pip cache dir)"
+        echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT
 
     - name: Cache
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: ${{ steps.pip-cache.outputs.dir }}
         key:
@@ -36,8 +36,14 @@
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
-        python -m pip install --upgrade tox tox-gh-actions
+        python -m pip install --upgrade tox tox-gh-actions coverage
 
     - name: Tox tests
       run: |
         tox -v
+
+    - name: Generate coverage XML report
+      run: coverage xml
+
+    - name: Codecov
+      uses: codecov/codecov-action@v3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/.gitignore 
new/django-rest-knox-5.0.1/.gitignore
--- old/django-rest-knox-4.2.0/.gitignore       2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/.gitignore       2024-07-19 18:36:00.000000000 
+0200
@@ -57,3 +57,6 @@
 target/
 db.sqlite3
 site/
+
+# PyCharm Project
+.idea
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/.pre-commit-config.yaml 
new/django-rest-knox-5.0.1/.pre-commit-config.yaml
--- old/django-rest-knox-4.2.0/.pre-commit-config.yaml  1970-01-01 
01:00:00.000000000 +0100
+++ new/django-rest-knox-5.0.1/.pre-commit-config.yaml  2024-07-19 
18:36:00.000000000 +0200
@@ -0,0 +1,9 @@
+repos:
+  - repo: https://github.com/PyCQA/isort
+    rev: 5.13.2
+    hooks:
+      - id: isort
+  - repo: https://github.com/PyCQA/flake8
+    rev: 7.1.0
+    hooks:
+      - id: flake8
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/CHANGELOG.md 
new/django-rest-knox-5.0.1/CHANGELOG.md
--- old/django-rest-knox-4.2.0/CHANGELOG.md     2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/CHANGELOG.md     2024-07-19 18:36:00.000000000 
+0200
@@ -1,7 +1,32 @@
+## 5.0.1
+- Fix migration: retrieve `TOKEN_MODEL` from `knox_settings` instead of Django 
settings.
+
+## 5.0.0
+- Tokens created prior to this release will no longer work
+- Fix migration reverse flow, enable migrate 0
+- Various documentation fixes and improvements
+- Drop `cryptography` in favor of hashlib
+- Make custom AuthModel work
+- Token prefix can be set in the setttings
+- Drop support for Django 4.0
+- Add support for Dango 4.2, 5.0 and Python 3.11 and 3.12
+- Cleanup legacy Python 2.0 code
+- Fix isort, flake8 usage for Python 3.10 in the test suite
+- Update Github actions version
+- Upgrade markdown dependency
+- Get rid of the `six` library
+- Add custom login / logout response support
+- Join the jazzband organization
+- Add pre-commit hooks
+- Add tracking of tests code coverage
+- Fix migrations when used in condition with a custom DB
+- Improve typing
+- Use `self.authenticate_header()` in `authenticate()` method to get auth 
header prefix
+
 ## 4.2.0
-- compatibility with Python up to 3.10 and Django up to 3.2
+- compatibility with Python up to 3.10 and Django up to 4.0
 - integration with github CI instead of travis
-- Migration: "salt" field of model "AuthToken" is removed
+- Migration: "salt" field of model "AuthToken" is removed, WARNING: 
invalidates old tokens!
 
 ## 4.1.0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/CONTRIBUTING.md 
new/django-rest-knox-5.0.1/CONTRIBUTING.md
--- old/django-rest-knox-4.2.0/CONTRIBUTING.md  1970-01-01 01:00:00.000000000 
+0100
+++ new/django-rest-knox-5.0.1/CONTRIBUTING.md  2024-07-19 18:36:00.000000000 
+0200
@@ -0,0 +1,3 @@
+[![Jazzband](https://jazzband.co/static/img/jazzband.svg)](https://jazzband.co/)
+
+This is a [Jazzband](https://jazzband.co/) project. By contributing you agree 
to abide by the [Contributor Code of 
Conduct](https://jazzband.co/about/conduct) and follow the 
[guidelines](https://jazzband.co/about/guidelines).
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/README.md 
new/django-rest-knox-5.0.1/README.md
--- old/django-rest-knox-4.2.0/README.md        2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/README.md        2024-07-19 18:36:00.000000000 
+0200
@@ -1,17 +1,18 @@
 django-rest-knox
 ================
 
-[![image](https://github.com/James1345/django-rest-knox/workflows/Test/badge.svg?branch=develop)](https://github.com/James1345/django-rest-knox/actions)
+[![Jazzband](https://jazzband.co/static/img/badge.svg)](https://jazzband.co/)
+[![image](https://github.com/jazzband/django-rest-knox/workflows/Test/badge.svg?branch=develop)](https://github.com/jazzband/django-rest-knox/actions)
 
-Authentication Module for django rest auth
+Authentication module for Django rest auth.
 
-Knox provides easy to use authentication for [Django REST
+Knox provides easy-to-use authentication for [Django REST
 Framework](https://www.django-rest-framework.org/) The aim is to allow
-for common patterns in applications that are REST based, with little
+for common patterns in applications that are REST-based, with little
 extra effort; and to ensure that connections remain secure.
 
-Knox authentication is token based, similar to the `TokenAuthentication`
-built in to DRF. However, it overcomes some problems present in the
+Knox authentication is token-based, similar to the `TokenAuthentication`
+built into DRF. However, it overcomes some problems present in the
 default implementation:
 
 -   DRF tokens are limited to one per user. This does not facilitate
@@ -23,13 +24,14 @@
     client to have its own token which is deleted on the server side
     when the client logs out.
 
-    Knox also provides an option for a logged in client to remove *all*
+    Knox also provides an option for a logged-in client to remove *all*
     tokens that the server has - forcing all clients to re-authenticate.
 
 -   DRF tokens are stored unencrypted in the database. This would allow
-    an attacker unrestricted access to an account with a token if the
+    an attacker unrestricted access to an account with a token if the 
     database were compromised.
 
+
     Knox tokens are only stored in a secure hash form (like a password). Even 
if the
     database were somehow stolen, an attacker would not be able to log
     in with the stolen credentials.
@@ -39,12 +41,11 @@
     the app settings (default is 10 hours.)
 
 More information can be found in the
-[Documentation](https://james1345.github.io/django-rest-knox/)
+[Documentation](https://jazzband.github.io/django-rest-knox/)
 
 # Run the tests locally
 
-If you need to debug a test locally and if you have 
[docker](https://www.docker.com/) installed:
-
+If you need to debug a test locally and if you have 
[docker](https://www.docker.com/) installed,
 simply run the ``./docker-run-tests.sh`` script and it will run the test suite 
in every Python /
 Django versions.
 
@@ -55,7 +56,7 @@
 
 Our documentation is generated by [Mkdocs](https://www.mkdocs.org).
 
-You can refer to their documentation on how to install it locally.
+You can refer to their 
[documentation](https://www.mkdocs.org/user-guide/installation/) on how to 
install it locally.
 
 Another option is to use `mkdocs.sh` in this repository.
 It will run mkdocs in a [docker](https://www.docker.com/) container.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/docs/auth.md 
new/django-rest-knox-5.0.1/docs/auth.md
--- old/django-rest-knox-4.2.0/docs/auth.md     2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/docs/auth.md     2024-07-19 18:36:00.000000000 
+0200
@@ -49,18 +49,17 @@
 
 For instance, you can authenticate users using Basic Authentication by simply 
overwriting knox's LoginView and setting BasicAuthentication as one of the 
acceptable authentication classes, as follows: 
 
+**views.py:**
 ```python
-
-views.py:
-
 from knox.views import LoginView as KnoxLoginView
 from rest_framework.authentication import BasicAuthentication
 
 class LoginView(KnoxLoginView):
     authentication_classes = [BasicAuthentication]
+```
 
-urls.py:
-
+**urls.py:**
+```python
 from knox import views as knox_views
 from yourapp.api.views import LoginView
 
@@ -75,10 +74,8 @@
 
 If you decide to use Token Authentication as your only authentication class, 
you can overwrite knox's login view as such:
 
+**views.py:**
 ```python
-
-views.py:
-
 from django.contrib.auth import login
 
 from rest_framework import permissions
@@ -94,9 +91,10 @@
         user = serializer.validated_data['user']
         login(request, user)
         return super(LoginView, self).post(request, format=None)
+```
 
-urls.py:
-
+**urls.py:**
+```python
 from knox import views as knox_views
 from yourapp.api.views import LoginView
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/docs/index.md 
new/django-rest-knox-5.0.1/docs/index.md
--- old/django-rest-knox-4.2.0/docs/index.md    2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/docs/index.md    2024-07-19 18:36:00.000000000 
+0200
@@ -1,10 +1,10 @@
 # Django-Rest-Knox
-Knox provides easy to use authentication for [Django REST 
Framework](https://www.django-rest-framework.org/)
+Knox provides easy-to-use authentication for [Django REST 
Framework](https://www.django-rest-framework.org/)
 The aim is to allow for common patterns in applications that are REST based,
 with little extra effort; and to ensure that connections remain secure.
 
 Knox authentication is token based, similar to the `TokenAuthentication` built
-in to DRF. However, it overcomes some problems present in the default 
implementation:
+into DRF. However, it overcomes some problems present in the default 
implementation:
 
 -   DRF tokens are limited to one per user. This does not facilitate securely
     signing in from multiple devices, as the token is shared. It also requires
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/docs/installation.md 
new/django-rest-knox-5.0.1/docs/installation.md
--- old/django-rest-knox-4.2.0/docs/installation.md     2022-01-31 
16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/docs/installation.md     2024-07-19 
18:36:00.000000000 +0200
@@ -2,27 +2,8 @@
 
 ## Requirements
 
-Knox depends on `cryptography` to provide bindings to `OpenSSL` for token 
generation
-This requires the OpenSSL build libraries to be available.
-
-### Windows
-Cryptography is a statically linked build, no extra steps are needed.
-
-### Linux
-`cryptography` should build very easily on Linux provided you have a C 
compiler,
-headers for Python (if you’re not using `pypy`), and headers for the OpenSSL 
and
-`libffi` libraries available on your system.
-
-Debian and Ubuntu:
-```bash
-sudo apt-get install build-essential libssl-dev libffi-dev python3-dev 
python-dev
-```
-
-Fedora and RHEL-derivatives:
-```bash
-sudo yum install gcc libffi-devel python-devel openssl-devel
-```
-For other systems or problems, see the [cryptography installation 
docs](https://cryptography.io/en/latest/installation/)
+Knox depends on pythons internal library `hashlib` to provide bindings to 
`OpenSSL` or uses
+an internal implementation of hashing algorithms for token generation.
 
 ## Installing Knox
 Knox should be installed with pip
@@ -59,7 +40,7 @@
 
 - If you set TokenAuthentication as the only default authentication class on 
the second step, [override knox's LoginView](auth.md#global-usage-on-all-views) 
to accept another authentication method and use it instead of knox's default 
login view.
 
-- Apply the migrations for the models
+- Apply the migrations for the models.
 
 ```bash
 python manage.py migrate
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/docs/settings.md 
new/django-rest-knox-5.0.1/docs/settings.md
--- old/django-rest-knox-4.2.0/docs/settings.md 2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/docs/settings.md 2024-07-19 18:36:00.000000000 
+0200
@@ -10,18 +10,27 @@
 # These are the default values if none are set
 from datetime import timedelta
 from rest_framework.settings import api_settings
+
+KNOX_TOKEN_MODEL = 'knox.AuthToken'
+
 REST_KNOX = {
-  'SECURE_HASH_ALGORITHM': 'cryptography.hazmat.primitives.hashes.SHA512',
+  'SECURE_HASH_ALGORITHM': 'hashlib.sha512',
   'AUTH_TOKEN_CHARACTER_LENGTH': 64,
   'TOKEN_TTL': timedelta(hours=10),
   'USER_SERIALIZER': 'knox.serializers.UserSerializer',
   'TOKEN_LIMIT_PER_USER': None,
   'AUTO_REFRESH': False,
+  'MIN_REFRESH_INTERVAL': 60,
+  'AUTH_HEADER_PREFIX': 'Token',
   'EXPIRY_DATETIME_FORMAT': api_settings.DATETIME_FORMAT,
+  'TOKEN_MODEL': 'knox.AuthToken',
 }
 #...snip...
 ```
 
+## KNOX_TOKEN_MODEL
+This is the variable used in the swappable dependency of the `AuthToken` model
+
 ## SECURE_HASH_ALGORITHM
 This is a reference to the class used to provide the hashing algorithm for
 token storage.
@@ -30,14 +39,13 @@
 
 By default, Knox uses SHA-512 to hash tokens in the database.
 
-`cryptography.hazmat.primitives.hashes.Whirlpool` is an acceptable alternative 
setting
-for production use.
+`hashlib.sha3_512` is an acceptable alternative setting for production use.
 
 ### Tests
-SHA-512 and Whirlpool are secure, however, they are slow. This should not be a
+SHA-512 and SHA3-512 are secure, however, they are slow. This should not be a
 problem for your users, but when testing it may be noticeable (as test cases 
tend
 to use many more requests much more quickly than real users). In testing 
scenarios
-it is acceptable to use `MD5` 
hashing.(`cryptography.hazmat.primitives.hashes.MD5`)
+it is acceptable to use `MD5` hashing (`hashlib.md5`).
 
 MD5 is **not secure** and must *never* be used in production sites.
 
@@ -58,7 +66,8 @@
 the system will not prevent you setting this.
 
 ## TOKEN_LIMIT_PER_USER
-This allows you to control how many tokens can be issued per user.
+This allows you to control how many valid tokens can be issued per user.
+If the limit for valid tokens is reached, an error is returned at login.
 By default this option is disabled and set to `None` -- thus no limit.
 
 ## USER_SERIALIZER
@@ -81,9 +90,18 @@
 [DATETIME_FORMAT][DATETIME_FORMAT] of Django REST framework. May be any of 
`None`, `iso-8601`
 or a Python [strftime format][strftime format] string.
 
+## TOKEN_MODEL
+This is the reference to the model used as `AuthToken`. We can define a custom 
`AuthToken`
+model in our project that extends `knox.AbstractAuthToken` and add our 
business logic to it.
+The default is `knox.AuthToken`
+
 [DATETIME_FORMAT]: 
https://www.django-rest-framework.org/api-guide/settings/#date-and-time-formatting
 [strftime format]: https://docs.python.org/3/library/time.html#time.strftime
 
+## TOKEN_PREFIX
+This is the prefix for the generated token that is used in the Authorization 
header. The default is just an empty string.
+It can be up to `CONSTANTS.MAXIMUM_TOKEN_PREFIX_LENGTH` long.
+
 # Constants `knox.settings`
 Knox also provides some constants for information. These must not be changed in
 external code; they are used in the model definitions in knox and an error will
@@ -97,3 +115,6 @@
 
 ## DIGEST_LENGTH
 This is the length of the digest that will be stored in the database for each 
token.
+
+## MAXIMUM_TOKEN_PREFIX_LENGTH
+This is the maximum length of the token prefix.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/docs/views.md 
new/django-rest-knox-5.0.1/docs/views.md
--- old/django-rest-knox-4.2.0/docs/views.md    2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/docs/views.md    2024-07-19 18:36:00.000000000 
+0200
@@ -21,6 +21,7 @@
 - `get_user_serializer_class(self)`, to change the class used for serializing 
the user
 - `get_expiry_datetime_format(self)`, to change the datetime format used for 
expiry
 - `format_expiry_datetime(self, expiry)`, to format the expiry `datetime` 
object at your convenience
+- `create_token(self)`, to create the `AuthToken` instance at your convenience
 
 Finally, if none of these helper methods are sufficient, you can also override 
`get_post_response_data`
 to return a fully customized payload.
@@ -66,12 +67,24 @@
 the token used to authenticate is deleted from the
 system and can no longer be used to authenticate.
 
+By default, this endpoint returns a HTTP 204 response on a successful request. 
To
+customize this behavior, you can override the `get_post_response` method, for 
example
+to include a body in the logout response and/or to modify the status code:
+
+```python
+...snip...
+    def get_post_response(self, request):
+        return Response({"bye-bye": request.user.username}, status=200)
+...snip...
+```
+
 ## LogoutAllView
 This view accepts only a post request with an empty body. It responds to Knox 
Token
 Authentication.
-On a successful request, the token used to authenticate, and *all other tokens*
-registered to the same `User` account, are deleted from the
-system and can no longer be used to authenticate.
+On a successful request, a HTTP 204 is returned and the token used to 
authenticate,
+and *all other tokens* registered to the same `User` account, are deleted from 
the
+system and can no longer be used to authenticate. The success response can be 
modified
+like the `LogoutView` by overriding the `get_post_response` method.
 
 **Note** It is not recommended to alter the Logout views. They are designed
 specifically for token management, and to respond to Knox authentication.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/knox/auth.py 
new/django-rest-knox-5.0.1/knox/auth.py
--- old/django-rest-knox-4.2.0/knox/auth.py     2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/knox/auth.py     2024-07-19 18:36:00.000000000 
+0200
@@ -1,10 +1,5 @@
-try:
-    from hmac import compare_digest
-except ImportError:
-    def compare_digest(a, b):
-        return a == b
-
 import binascii
+from hmac import compare_digest
 
 from django.utils import timezone
 from django.utils.translation import gettext_lazy as _
@@ -14,7 +9,7 @@
 )
 
 from knox.crypto import hash_token
-from knox.models import AuthToken
+from knox.models import get_token_model
 from knox.settings import CONSTANTS, knox_settings
 from knox.signals import token_expired
 
@@ -31,11 +26,10 @@
     - `request.user` will be a django `User` instance
     - `request.auth` will be an `AuthToken` instance
     '''
-    model = AuthToken
 
     def authenticate(self, request):
         auth = get_authorization_header(request).split()
-        prefix = knox_settings.AUTH_HEADER_PREFIX.encode()
+        prefix = self.authenticate_header(request).encode()
 
         if not auth:
             return None
@@ -62,7 +56,7 @@
         '''
         msg = _('Invalid token.')
         token = token.decode("utf-8")
-        for auth_token in AuthToken.objects.filter(
+        for auth_token in get_token_model().objects.filter(
                 token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH]):
             if self._cleanup_token(auth_token):
                 continue
@@ -77,7 +71,7 @@
                 return self.validate_user(auth_token)
         raise exceptions.AuthenticationFailed(msg)
 
-    def renew_token(self, auth_token):
+    def renew_token(self, auth_token) -> None:
         current_expiry = auth_token.expiry
         new_expiry = timezone.now() + knox_settings.TOKEN_TTL
         auth_token.expiry = new_expiry
@@ -95,7 +89,7 @@
     def authenticate_header(self, request):
         return knox_settings.AUTH_HEADER_PREFIX
 
-    def _cleanup_token(self, auth_token):
+    def _cleanup_token(self, auth_token) -> bool:
         for other_token in auth_token.user.auth_token_set.all():
             if other_token.digest != auth_token.digest and other_token.expiry:
                 if other_token.expiry < timezone.now():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/knox/crypto.py 
new/django-rest-knox-5.0.1/knox/crypto.py
--- old/django-rest-knox-4.2.0/knox/crypto.py   2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/knox/crypto.py   2024-07-19 18:36:00.000000000 
+0200
@@ -1,28 +1,31 @@
 import binascii
 from os import urandom as generate_bytes
 
-from cryptography.hazmat.backends import default_backend
-from cryptography.hazmat.primitives import hashes
-
 from knox.settings import knox_settings
 
-sha = knox_settings.SECURE_HASH_ALGORITHM
+hash_func = knox_settings.SECURE_HASH_ALGORITHM
 
 
-def create_token_string():
+def create_token_string() -> str:
     return binascii.hexlify(
         generate_bytes(int(knox_settings.AUTH_TOKEN_CHARACTER_LENGTH / 2))
     ).decode()
 
 
-def hash_token(token):
-    '''
-    Calculates the hash of a token.
-    input is unhexlified
+def make_hex_compatible(token: str) -> bytes:
+    """
+    We need to make sure that the token, that is send is hex-compatible.
+    When a token prefix is used, we cannot guarantee that.
+    """
+    return binascii.unhexlify(binascii.hexlify(bytes(token, 'utf-8')))
 
-    token must contain an even number of hex digits or a binascii.Error
-    exception will be raised
-    '''
-    digest = hashes.Hash(sha(), backend=default_backend())
-    digest.update(binascii.unhexlify(token))
-    return binascii.hexlify(digest.finalize()).decode()
+
+def hash_token(token: str) -> str:
+    """
+    Calculates the hash of a token.
+    Token must contain an even number of hex digits or
+    a binascii.Error exception will be raised.
+    """
+    digest = hash_func()
+    digest.update(make_hex_compatible(token))
+    return digest.hexdigest()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-rest-knox-4.2.0/knox/migrations/0001_initial.py 
new/django-rest-knox-5.0.1/knox/migrations/0001_initial.py
--- old/django-rest-knox-4.2.0/knox/migrations/0001_initial.py  2022-01-31 
16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/knox/migrations/0001_initial.py  2024-07-19 
18:36:00.000000000 +0200
@@ -4,11 +4,14 @@
 from django.conf import settings
 from django.db import migrations, models
 
+from knox.settings import knox_settings
+
 
 class Migration(migrations.Migration):
 
     dependencies = [
         migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        migrations.swappable_dependency(knox_settings.TOKEN_MODEL),
     ]
 
     operations = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-rest-knox-4.2.0/knox/migrations/0006_auto_20160818_0932.py 
new/django-rest-knox-5.0.1/knox/migrations/0006_auto_20160818_0932.py
--- old/django-rest-knox-4.2.0/knox/migrations/0006_auto_20160818_0932.py       
2022-01-31 16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/knox/migrations/0006_auto_20160818_0932.py       
2024-07-19 18:36:00.000000000 +0200
@@ -7,7 +7,7 @@
 
 def cleanup_tokens(apps, schema_editor):
     AuthToken = apps.get_model('knox', 'AuthToken')
-    AuthToken.objects.filter(token_key__isnull=True).delete()
+    
AuthToken.objects.using(schema_editor.connection.alias).filter(token_key__isnull=True).delete()
 
 
 class Migration(migrations.Migration):
@@ -17,7 +17,7 @@
     ]
 
     operations = [
-        migrations.RunPython(cleanup_tokens),
+        migrations.RunPython(cleanup_tokens, 
reverse_code=migrations.RunPython.noop),
         migrations.AlterField(
             model_name='authtoken',
             name='token_key',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/django-rest-knox-4.2.0/knox/migrations/0009_extend_authtoken_field.py 
new/django-rest-knox-5.0.1/knox/migrations/0009_extend_authtoken_field.py
--- old/django-rest-knox-4.2.0/knox/migrations/0009_extend_authtoken_field.py   
1970-01-01 01:00:00.000000000 +0100
+++ new/django-rest-knox-5.0.1/knox/migrations/0009_extend_authtoken_field.py   
2024-07-19 18:36:00.000000000 +0200
@@ -0,0 +1,18 @@
+# Generated by Django 4.1rc1 on 2022-07-20 17:05
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("knox", "0008_remove_authtoken_salt"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="authtoken",
+            name="token_key",
+            field=models.CharField(db_index=True, max_length=25),
+        ),
+    ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/knox/models.py 
new/django-rest-knox-5.0.1/knox/models.py
--- old/django-rest-knox-4.2.0/knox/models.py   2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/knox/models.py   2024-07-19 18:36:00.000000000 
+0200
@@ -1,39 +1,76 @@
+from django.apps import apps
 from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
 from django.db import models
 from django.utils import timezone
 
 from knox import crypto
 from knox.settings import CONSTANTS, knox_settings
 
+sha = knox_settings.SECURE_HASH_ALGORITHM
+
 User = settings.AUTH_USER_MODEL
 
 
 class AuthTokenManager(models.Manager):
-    def create(self, user, expiry=knox_settings.TOKEN_TTL):
-        token = crypto.create_token_string()
+    def create(
+        self,
+        user,
+        expiry=knox_settings.TOKEN_TTL,
+        prefix=knox_settings.TOKEN_PREFIX,
+        **kwargs
+    ):
+        token = prefix + crypto.create_token_string()
         digest = crypto.hash_token(token)
-
         if expiry is not None:
             expiry = timezone.now() + expiry
-
         instance = super(AuthTokenManager, self).create(
             token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH], digest=digest,
-            user=user, expiry=expiry)
+            user=user, expiry=expiry, **kwargs)
         return instance, token
 
 
-class AuthToken(models.Model):
+class AbstractAuthToken(models.Model):
 
     objects = AuthTokenManager()
 
     digest = models.CharField(
         max_length=CONSTANTS.DIGEST_LENGTH, primary_key=True)
     token_key = models.CharField(
-        max_length=CONSTANTS.TOKEN_KEY_LENGTH, db_index=True)
+        max_length=CONSTANTS.MAXIMUM_TOKEN_PREFIX_LENGTH +
+        CONSTANTS.TOKEN_KEY_LENGTH,
+        db_index=True
+    )
     user = models.ForeignKey(User, null=False, blank=False,
                              related_name='auth_token_set', 
on_delete=models.CASCADE)
     created = models.DateTimeField(auto_now_add=True)
     expiry = models.DateTimeField(null=True, blank=True)
 
-    def __str__(self):
-        return '%s : %s' % (self.digest, self.user)
+    class Meta:
+        abstract = True
+
+    def __str__(self) -> str:
+        return f'{self.digest} : {self.user}'
+
+
+class AuthToken(AbstractAuthToken):
+    class Meta:
+        swappable = 'KNOX_TOKEN_MODEL'
+
+
+def get_token_model():
+    """
+    Return the AuthToken model that is active in this project.
+    """
+
+    try:
+        return apps.get_model(knox_settings.TOKEN_MODEL, require_ready=False)
+    except ValueError:
+        raise ImproperlyConfigured(
+            "TOKEN_MODEL must be of the form 'app_label.model_name'"
+        )
+    except LookupError:
+        raise ImproperlyConfigured(
+            "TOKEN_MODEL refers to model '%s' that has not been installed"
+            % knox_settings.TOKEN_MODEL
+        )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/knox/settings.py 
new/django-rest-knox-5.0.1/knox/settings.py
--- old/django-rest-knox-4.2.0/knox/settings.py 2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/knox/settings.py 2024-07-19 18:36:00.000000000 
+0200
@@ -1,13 +1,13 @@
 from datetime import timedelta
 
 from django.conf import settings
-from django.test.signals import setting_changed
+from django.core.signals import setting_changed
 from rest_framework.settings import APISettings, api_settings
 
 USER_SETTINGS = getattr(settings, 'REST_KNOX', None)
 
 DEFAULTS = {
-    'SECURE_HASH_ALGORITHM': 'cryptography.hazmat.primitives.hashes.SHA512',
+    'SECURE_HASH_ALGORITHM': 'hashlib.sha512',
     'AUTH_TOKEN_CHARACTER_LENGTH': 64,
     'TOKEN_TTL': timedelta(hours=10),
     'USER_SERIALIZER': None,
@@ -16,6 +16,8 @@
     'MIN_REFRESH_INTERVAL': 60,
     'AUTH_HEADER_PREFIX': 'Token',
     'EXPIRY_DATETIME_FORMAT': api_settings.DATETIME_FORMAT,
+    'TOKEN_MODEL': getattr(settings, 'KNOX_TOKEN_MODEL', 'knox.AuthToken'),
+    'TOKEN_PREFIX': '',
 }
 
 IMPORT_STRINGS = {
@@ -31,6 +33,8 @@
     setting, value = kwargs['setting'], kwargs['value']
     if setting == 'REST_KNOX':
         knox_settings = APISettings(value, DEFAULTS, IMPORT_STRINGS)
+        if len(knox_settings.TOKEN_PREFIX) > 
CONSTANTS.MAXIMUM_TOKEN_PREFIX_LENGTH:
+            raise ValueError("Illegal TOKEN_PREFIX length")
 
 
 setting_changed.connect(reload_api_settings)
@@ -40,8 +44,9 @@
     '''
     Constants cannot be changed at runtime
     '''
-    TOKEN_KEY_LENGTH = 8
+    TOKEN_KEY_LENGTH = 15
     DIGEST_LENGTH = 128
+    MAXIMUM_TOKEN_PREFIX_LENGTH = 10
 
     def __setattr__(self, *args, **kwargs):
         raise Exception('''
@@ -50,4 +55,4 @@
             ''')
 
 
-CONSTANTS = CONSTANTS()
+CONSTANTS = CONSTANTS()  # type: ignore
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/knox/views.py 
new/django-rest-knox-5.0.1/knox/views.py
--- old/django-rest-knox-4.2.0/knox/views.py    2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/knox/views.py    2024-07-19 18:36:00.000000000 
+0200
@@ -8,7 +8,7 @@
 from rest_framework.views import APIView
 
 from knox.auth import TokenAuthentication
-from knox.models import AuthToken
+from knox.models import get_token_model
 from knox.settings import knox_settings
 
 
@@ -22,6 +22,9 @@
     def get_token_ttl(self):
         return knox_settings.TOKEN_TTL
 
+    def get_token_prefix(self):
+        return knox_settings.TOKEN_PREFIX
+
     def get_token_limit_per_user(self):
         return knox_settings.TOKEN_LIMIT_PER_USER
 
@@ -35,6 +38,12 @@
         datetime_format = self.get_expiry_datetime_format()
         return DateTimeField(format=datetime_format).to_representation(expiry)
 
+    def create_token(self):
+        token_prefix = self.get_token_prefix()
+        return get_token_model().objects.create(
+            user=self.request.user, expiry=self.get_token_ttl(), 
prefix=token_prefix
+        )
+
     def get_post_response_data(self, request, token, instance):
         UserSerializer = self.get_user_serializer_class()
 
@@ -49,6 +58,10 @@
             ).data
         return data
 
+    def get_post_response(self, request, token, instance):
+        data = self.get_post_response_data(request, token, instance)
+        return Response(data)
+
     def post(self, request, format=None):
         token_limit_per_user = self.get_token_limit_per_user()
         if token_limit_per_user is not None:
@@ -59,23 +72,24 @@
                     {"error": "Maximum amount of tokens allowed per user 
exceeded."},
                     status=status.HTTP_403_FORBIDDEN
                 )
-        token_ttl = self.get_token_ttl()
-        instance, token = AuthToken.objects.create(request.user, token_ttl)
+        instance, token = self.create_token()
         user_logged_in.send(sender=request.user.__class__,
                             request=request, user=request.user)
-        data = self.get_post_response_data(request, token, instance)
-        return Response(data)
+        return self.get_post_response(request, token, instance)
 
 
 class LogoutView(APIView):
     authentication_classes = (TokenAuthentication,)
     permission_classes = (IsAuthenticated,)
 
+    def get_post_response(self, request):
+        return Response(None, status=status.HTTP_204_NO_CONTENT)
+
     def post(self, request, format=None):
         request._auth.delete()
         user_logged_out.send(sender=request.user.__class__,
                              request=request, user=request.user)
-        return Response(None, status=status.HTTP_204_NO_CONTENT)
+        return self.get_post_response(request)
 
 
 class LogoutAllView(APIView):
@@ -86,8 +100,11 @@
     authentication_classes = (TokenAuthentication,)
     permission_classes = (IsAuthenticated,)
 
+    def get_post_response(self, request):
+        return Response(None, status=status.HTTP_204_NO_CONTENT)
+
     def post(self, request, format=None):
         request.user.auth_token_set.all().delete()
         user_logged_out.send(sender=request.user.__class__,
                              request=request, user=request.user)
-        return Response(None, status=status.HTTP_204_NO_CONTENT)
+        return self.get_post_response(request)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/knox_project/settings.py 
new/django-rest-knox-5.0.1/knox_project/settings.py
--- old/django-rest-knox-4.2.0/knox_project/settings.py 2022-01-31 
16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/knox_project/settings.py 2024-07-19 
18:36:00.000000000 +0200
@@ -49,7 +49,9 @@
 LANGUAGE_CODE = 'en-us'
 TIME_ZONE = 'UTC'
 USE_I18N = True
-USE_L10N = True
+USE_L10N = True  # Deprecated since django 4.0.
 USE_TZ = True
 
 STATIC_URL = '/static/'
+
+KNOX_TOKEN_MODEL = 'knox.AuthToken'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/mkdocs.sh 
new/django-rest-knox-5.0.1/mkdocs.sh
--- old/django-rest-knox-4.2.0/mkdocs.sh        2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/mkdocs.sh        2024-07-19 18:36:00.000000000 
+0200
@@ -9,4 +9,4 @@
     -w $MOUNT_FOLDER \
     -p $MKDOCS_DEV_PORT:$MKDOCS_DEV_PORT \
     -e MKDOCS_DEV_ADDR="$MKDOCS_DEV_ADDR:$MKDOCS_DEV_PORT" \
-    squidfunk/mkdocs-material:3.2.0 $*
+    squidfunk/mkdocs-material:latest $*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/mkdocs.yml 
new/django-rest-knox-5.0.1/mkdocs.yml
--- old/django-rest-knox-4.2.0/mkdocs.yml       2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/mkdocs.yml       2024-07-19 18:36:00.000000000 
+0200
@@ -1,5 +1,5 @@
 site_name: Django-Rest-Knox
-repo_url: https://github.com/James1345/django-rest-knox
+repo_url: https://github.com/jazzband/django-rest-knox
 theme: readthedocs
 nav:
   - Home: 'index.md'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/setup.py 
new/django-rest-knox-5.0.1/setup.py
--- old/django-rest-knox-4.2.0/setup.py 2022-01-31 16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/setup.py 2024-07-19 18:36:00.000000000 +0200
@@ -17,13 +17,13 @@
     # Versions should comply with PEP440.  For a discussion on single-sourcing
     # the version across setup.py and the project code, see
     # https://packaging.python.org/en/latest/single_source_version.html
-    version='4.2.0',
+    version='5.0.1',
     description='Authentication for django rest framework',
     long_description=long_description,
     long_description_content_type='text/markdown',
 
     # The project's main homepage.
-    url='https://github.com/James1345/django-rest-knox',
+    url='https://github.com/jazzband/django-rest-knox',
 
     # Author details
     author='James McMahon',
@@ -51,6 +51,8 @@
         'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: 3.9',
         'Programming Language :: Python :: 3.10',
+        'Programming Language :: Python :: 3.11',
+        'Programming Language :: Python :: 3.12',
     ],
 
     # What does your project relate to?
@@ -69,7 +71,6 @@
     install_requires=[
         'django>=3.2',
         'djangorestframework',
-        'cryptography',
     ],
 
     # List additional groups of dependencies here (e.g. development
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/tests/tests.py 
new/django-rest-knox-5.0.1/tests/tests.py
--- old/django-rest-knox-4.2.0/tests/tests.py   2022-01-31 16:24:27.000000000 
+0100
+++ new/django-rest-knox-5.0.1/tests/tests.py   2024-07-19 18:36:00.000000000 
+0200
@@ -1,5 +1,6 @@
 import base64
 from datetime import datetime, timedelta
+from importlib import reload
 
 from django.contrib.auth import get_user_model
 from django.test import override_settings
@@ -8,9 +9,8 @@
 from rest_framework.exceptions import AuthenticationFailed
 from rest_framework.serializers import DateTimeField
 from rest_framework.test import APIRequestFactory, APITestCase as TestCase
-from six.moves import reload_module
 
-from knox import auth, views
+from knox import auth, crypto, views
 from knox.auth import TokenAuthentication
 from knox.models import AuthToken
 from knox.serializers import UserSerializer
@@ -23,7 +23,7 @@
 
 def get_basic_auth_header(username, password):
     return 'Basic %s' % base64.b64encode(
-        ('%s:%s' % (username, password)).encode('ascii')).decode()
+        (f'{username}:{password}').encode('ascii')).decode()
 
 
 auto_refresh_knox = knox_settings.defaults.copy()
@@ -45,6 +45,14 @@
 expiry_datetime_format_knox = knox_settings.defaults.copy()
 expiry_datetime_format_knox["EXPIRY_DATETIME_FORMAT"] = EXPIRY_DATETIME_FORMAT
 
+token_prefix = "TEST_"
+token_prefix_knox = knox_settings.defaults.copy()
+token_prefix_knox["TOKEN_PREFIX"] = token_prefix
+
+token_prefix_too_long = "a" * CONSTANTS.MAXIMUM_TOKEN_PREFIX_LENGTH + "a"
+token_prefix_too_long_knox = knox_settings.defaults.copy()
+token_prefix_too_long_knox["TOKEN_PREFIX"] = token_prefix_too_long
+
 
 class AuthTestCase(TestCase):
 
@@ -86,7 +94,7 @@
     def test_login_returns_serialized_token_and_username_field(self):
 
         with override_settings(REST_KNOX=user_serializer_knox):
-            reload_module(views)
+            reload(views)
             self.assertEqual(AuthToken.objects.count(), 0)
             url = reverse('knox_login')
             self.client.credentials(
@@ -94,7 +102,7 @@
             )
             response = self.client.post(url, {}, format='json')
             self.assertEqual(user_serializer_knox["USER_SERIALIZER"], 
UserSerializer)
-        reload_module(views)
+        (views)
         self.assertEqual(response.status_code, 200)
         self.assertIn('token', response.data)
         username_field = self.user.USERNAME_FIELD
@@ -104,7 +112,7 @@
     def test_login_returns_configured_expiry_datetime_format(self):
 
         with override_settings(REST_KNOX=expiry_datetime_format_knox):
-            reload_module(views)
+            reload(views)
             self.assertEqual(AuthToken.objects.count(), 0)
             url = reverse('knox_login')
             self.client.credentials(
@@ -115,7 +123,7 @@
                 expiry_datetime_format_knox["EXPIRY_DATETIME_FORMAT"],
                 EXPIRY_DATETIME_FORMAT
             )
-        reload_module(views)
+        reload(views)
         self.assertEqual(response.status_code, 200)
         self.assertIn('token', response.data)
         self.assertNotIn('user', response.data)
@@ -190,7 +198,7 @@
         instance, token = AuthToken.objects.create(self.user)
         rf = APIRequestFactory()
         request = rf.get('/')
-        request.META = {'HTTP_AUTHORIZATION': 'Token {}'.format(token)}
+        request.META = {'HTTP_AUTHORIZATION': f'Token {token}'}
         (self.user, auth_token) = TokenAuthentication().authenticate(request)
         self.assertEqual(
             token[:CONSTANTS.TOKEN_KEY_LENGTH],
@@ -250,10 +258,10 @@
         self.client.credentials(HTTP_AUTHORIZATION=('Token %s' % token))
         five_hours_later = original_time + timedelta(hours=5)
         with override_settings(REST_KNOX=auto_refresh_knox):
-            reload_module(auth)  # necessary to reload settings in core code
+            reload(auth)  # necessary to reload settings in core code
             with freeze_time(five_hours_later):
                 response = self.client.get(root_url, {}, format='json')
-        reload_module(auth)
+        reload(auth)
         self.assertEqual(response.status_code, 200)
 
         # original expiry date was extended:
@@ -302,10 +310,10 @@
         self.client.credentials(HTTP_AUTHORIZATION=('Token %s' % token))
         in_min_interval = now + 
timedelta(seconds=knox_settings.MIN_REFRESH_INTERVAL - 10)
         with override_settings(REST_KNOX=auto_refresh_knox):
-            reload_module(auth)  # necessary to reload settings in core code
+            reload(auth)  # necessary to reload settings in core code
             with freeze_time(in_min_interval):
                 response = self.client.get(root_url, {}, format='json')
-        reload_module(auth)  # necessary to reload settings in core code
+        reload(auth)  # necessary to reload settings in core code
 
         self.assertEqual(response.status_code, 200)
         self.assertEqual(original_expiry, AuthToken.objects.get().expiry)
@@ -318,7 +326,10 @@
 
         token_expired.connect(handler)
 
-        instance, token = AuthToken.objects.create(user=self.user, 
expiry=timedelta(seconds=-1))
+        instance, token = AuthToken.objects.create(
+            user=self.user,
+            expiry=timedelta(seconds=-1),
+        )
         self.client.credentials(HTTP_AUTHORIZATION=('Token %s' % token))
         self.client.post(root_url, {}, format='json')
 
@@ -327,7 +338,7 @@
     def test_exceed_token_amount_per_user(self):
 
         with override_settings(REST_KNOX=token_user_limit_knox):
-            reload_module(views)
+            reload(views)
             for _ in range(10):
                 AuthToken.objects.create(user=self.user)
             url = reverse('knox_login')
@@ -335,7 +346,7 @@
                 HTTP_AUTHORIZATION=get_basic_auth_header(self.username, 
self.password)
             )
             response = self.client.post(url, {}, format='json')
-        reload_module(views)
+        reload(views)
         self.assertEqual(response.status_code, 403)
         self.assertEqual(response.data,
                          {"error": "Maximum amount of tokens allowed per user 
exceeded."})
@@ -343,7 +354,7 @@
     def test_does_not_exceed_on_expired_keys(self):
 
         with override_settings(REST_KNOX=token_user_limit_knox):
-            reload_module(views)
+            reload(views)
             for _ in range(9):
                 AuthToken.objects.create(user=self.user)
             AuthToken.objects.create(user=self.user, 
expiry=timedelta(seconds=-1))
@@ -354,7 +365,7 @@
             )
             response = self.client.post(url, {}, format='json')
             failed_response = self.client.post(url, {}, format='json')
-        reload_module(views)
+        reload(views)
         self.assertEqual(response.status_code, 200)
         self.assertIn('token', response.data)
         self.assertEqual(failed_response.status_code, 403)
@@ -364,7 +375,7 @@
     def test_invalid_prefix_return_401(self):
 
         with override_settings(REST_KNOX=auth_header_prefix_knox):
-            reload_module(auth)
+            reload(auth)
             instance, token = AuthToken.objects.create(user=self.user)
             self.client.credentials(HTTP_AUTHORIZATION=('Token %s' % token))
             failed_response = self.client.get(root_url)
@@ -374,13 +385,13 @@
                 )
             )
             response = self.client.get(root_url)
-        reload_module(auth)
+        reload(auth)
         self.assertEqual(failed_response.status_code, 401)
         self.assertEqual(response.status_code, 200)
 
     def test_expiry_present_also_when_none(self):
         with override_settings(REST_KNOX=token_no_expiration_knox):
-            reload_module(views)
+            reload(views)
             self.assertEqual(AuthToken.objects.count(), 0)
             url = reverse('knox_login')
             self.client.credentials(
@@ -399,7 +410,7 @@
                 response.data['expiry'],
                 None
             )
-        reload_module(views)
+        reload(views)
 
     def test_expiry_is_present(self):
         self.assertEqual(AuthToken.objects.count(), 0)
@@ -419,3 +430,69 @@
             response.data['expiry'],
             DateTimeField().to_representation(AuthToken.objects.first().expiry)
         )
+
+    def test_login_returns_serialized_token_with_prefix_when_prefix_set(self):
+        with override_settings(REST_KNOX=token_prefix_knox):
+            reload(views)
+            reload(crypto)
+            self.assertEqual(AuthToken.objects.count(), 0)
+            url = reverse('knox_login')
+            self.client.credentials(
+                HTTP_AUTHORIZATION=get_basic_auth_header(self.username, 
self.password)
+            )
+            response = self.client.post(
+                url,
+                {},
+                format='json'
+            )
+            self.assertEqual(response.status_code, 200)
+            self.assertTrue(response.data['token'].startswith(token_prefix))
+        reload(views)
+        reload(crypto)
+
+    def test_token_with_prefix_returns_200(self):
+        with override_settings(REST_KNOX=token_prefix_knox):
+            reload(views)
+            self.assertEqual(AuthToken.objects.count(), 0)
+            url = reverse('knox_login')
+            self.client.credentials(
+                HTTP_AUTHORIZATION=get_basic_auth_header(self.username, 
self.password)
+            )
+            response = self.client.post(
+                url,
+                {},
+                format='json'
+            )
+            self.assertEqual(response.status_code, 200)
+            self.assertTrue(response.data['token'].startswith(token_prefix))
+            self.client.credentials(
+                HTTP_AUTHORIZATION=('Token %s' % response.data['token'])
+            )
+            response = self.client.get(root_url, {}, format='json')
+            self.assertEqual(response.status_code, 200)
+        reload(views)
+
+    def test_prefix_set_longer_than_max_length_raises_valueerror(self):
+        with self.assertRaises(ValueError):
+            with override_settings(REST_KNOX=token_prefix_too_long_knox):
+                pass
+
+    def test_tokens_created_before_prefix_still_work(self):
+        self.client.credentials(
+            HTTP_AUTHORIZATION=get_basic_auth_header(self.username, 
self.password)
+        )
+        url = reverse('knox_login')
+        response = self.client.post(
+            url,
+            {},
+            format='json'
+        )
+        self.assertFalse(response.data['token'].startswith(token_prefix))
+        with override_settings(REST_KNOX=token_prefix_knox):
+            reload(views)
+            self.client.credentials(
+                HTTP_AUTHORIZATION=('Token %s' % response.data['token'])
+            )
+            response = self.client.get(root_url, {}, format='json')
+            self.assertEqual(response.status_code, 200)
+        reload(views)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/django-rest-knox-4.2.0/tox.ini 
new/django-rest-knox-5.0.1/tox.ini
--- old/django-rest-knox-4.2.0/tox.ini  2022-01-31 16:24:27.000000000 +0100
+++ new/django-rest-knox-5.0.1/tox.ini  2024-07-19 18:36:00.000000000 +0200
@@ -1,49 +1,37 @@
 [tox]
 envlist =
-    isort,
-    flake8,
     py{36,37,38,39,310}-django32,
-    py{38,39,310}-django40,
-
-[testenv:flake8]
-deps = flake8
-changedir = {toxinidir}
-commands = flake8 knox
-
-[testenv:isort]
-deps = isort
-changedir = {toxinidir}
-commands = isort --check-only --diff \
-    knox \
-    knox_project/views.py \
-    setup.py \
-    tests
+    py{38,39,310,311,312}-django42,
+    py{310,311,312}-django50,
 
 [testenv]
 commands =
     python manage.py migrate
-    python manage.py test
+    coverage run manage.py test
+    coverage report
 setenv =
     DJANGO_SETTINGS_MODULE = knox_project.settings
     PIP_INDEX_URL = https://pypi.python.org/simple/
 deps =
     django32: Django>=3.2,<3.3
-    django40: Django>=4.0,<4.1
-    markdown<3.0
-    isort>=5.0
+    django42: Django>=4.2,<4.3
+    django50: Django>=5.0,<5.1
+    markdown>=3.0
     djangorestframework
     freezegun
     mkdocs
-    cryptography
     pytest-django
     setuptools
     twine
     wheel
+    coverage
 
 [gh-actions]
 python =
     3.6: py36
     3.7: py37
     3.8: py38
-    3.9: py39, isort, flake8
+    3.9: py39
     3.10: py310
+    3.11: py311
+    3.12: py312

Reply via email to