django-pfx 1.4.dev42__tar.gz → 1.4.dev46__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/PKG-INFO +1 -1
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/django_pfx.egg-info/PKG-INFO +1 -1
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/default_settings.py +1 -0
- django_pfx-1.4.dev46/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +15 -11
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/middleware/authentication.py +6 -6
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/models/otp_user_mixin.py +5 -2
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/authentication_views.py +18 -9
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_auth_api.py +8 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_settings.py +1 -3
- django_pfx-1.4.dev42/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/.gitignore +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/.gitlab-ci.yml +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/.pre-commit-config.yaml +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/LICENSE +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/MANIFEST.in +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/README.md +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/django_pfx.egg-info/SOURCES.txt +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/django_pfx.egg-info/dependency_links.txt +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/django_pfx.egg-info/requires.txt +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/django_pfx.egg-info/top_level.txt +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/Makefile +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/conf.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/index.rst +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/source/api.views.rst +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/source/authentication.md +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/source/decorator.md +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/source/generate_openapi.md +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/source/getting_started.md +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/source/internationalisation.md +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/source/model.md +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/source/pfx_views.md +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/source/profiling.md +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/source/settings.md +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/doc/source/testing.md +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/img/pfx.png +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/img/pfx.svg +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/make_messages +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/manage.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/apidoc/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/apidoc/parameters.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/apidoc/schema.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/apidoc/tags.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/apps.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/decorator/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/decorator/rest.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/exceptions.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/fields.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/http/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/http/json_response.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/management/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/management/commands/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/management/commands/profile.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/middleware/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/middleware/locale.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/middleware/profiling.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/migrations/0001_initial.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/migrations/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/models/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/models/cache_mixins.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/models/login_ban.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/models/not_null_fields.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/models/pfx_models.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/models/pfx_user.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/serializers/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/serializers/json.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/settings.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/shortcuts.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/storage/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/storage/s3_storage.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/test.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/urls.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/fields.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/filters_views.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/locale_views.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/date_format.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/groups.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/list_count.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/list_items.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/list_order.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/list_search.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/subset.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/rest_views.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/settings/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/settings/dev.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pyproject.toml +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/requirements.txt +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/serve-doc +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/setup.cfg +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/setup.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/models.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/settings/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/settings/ci.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/settings/common.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/settings/dev.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/settings/dev_custom_example.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/settings/dev_default.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/__init__.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/basic_api_errors.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/basic_api_test.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_api_doc.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_body_mixin.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_cache.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_client.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_fields.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_filters.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_locale_api.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_perm_tests.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_perms_api.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_profiling_middleware.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_shortcuts.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_timezone_middleware.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_tools.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_user_queryset.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_view_decorators.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/tests/test_view_fields.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/urls.py +0 -0
- {django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/tests/views.py +0 -0
|
Binary file
|
|
@@ -7,7 +7,7 @@ msgid ""
|
|
|
7
7
|
msgstr ""
|
|
8
8
|
"Project-Id-Version: \n"
|
|
9
9
|
"Report-Msgid-Bugs-To: \n"
|
|
10
|
-
"POT-Creation-Date: 2024-04-
|
|
10
|
+
"POT-Creation-Date: 2024-04-23 14:41+0200\n"
|
|
11
11
|
"PO-Revision-Date: 2021-06-22 23:31+0200\n"
|
|
12
12
|
"Last-Translator: \n"
|
|
13
13
|
"Language-Team: \n"
|
|
@@ -95,7 +95,7 @@ msgstr "Compte HOTP"
|
|
|
95
95
|
msgid "HOTP expiry"
|
|
96
96
|
msgstr "Expiration HOTP"
|
|
97
97
|
|
|
98
|
-
#: models/otp_user_mixin.py:29 views/authentication_views.py:
|
|
98
|
+
#: models/otp_user_mixin.py:29 views/authentication_views.py:496
|
|
99
99
|
msgid "OTP enabled"
|
|
100
100
|
msgstr "OTP activé"
|
|
101
101
|
|
|
@@ -205,7 +205,11 @@ msgstr ""
|
|
|
205
205
|
"Votre connexion est temporairement désactivée après plusieurs tentatives "
|
|
206
206
|
"infructueuses, veuillez réessayer dans {seconds} secondes."
|
|
207
207
|
|
|
208
|
-
#: views/authentication_views.py:
|
|
208
|
+
#: views/authentication_views.py:173
|
|
209
|
+
msgid "Successful login"
|
|
210
|
+
msgstr "Connexion réussie"
|
|
211
|
+
|
|
212
|
+
#: views/authentication_views.py:243 views/authentication_views.py:413
|
|
209
213
|
msgid "password updated successfully"
|
|
210
214
|
msgstr "le mot de passe a été mis à jour avec succès"
|
|
211
215
|
|
|
@@ -213,31 +217,31 @@ msgstr "le mot de passe a été mis à jour avec succès"
|
|
|
213
217
|
msgid "Incorrect password"
|
|
214
218
|
msgstr "Mot de passe incorrect"
|
|
215
219
|
|
|
216
|
-
#: views/authentication_views.py:251 views/authentication_views.py:
|
|
220
|
+
#: views/authentication_views.py:251 views/authentication_views.py:422
|
|
217
221
|
msgid "Empty password is not allowed"
|
|
218
222
|
msgstr "Un mot de passe vide n’est pas autorisé"
|
|
219
223
|
|
|
220
|
-
#: views/authentication_views.py:
|
|
224
|
+
#: views/authentication_views.py:347
|
|
221
225
|
msgid "User and token are valid"
|
|
222
226
|
msgstr "L'utilisateur et le token sont valides"
|
|
223
227
|
|
|
224
|
-
#: views/authentication_views.py:
|
|
228
|
+
#: views/authentication_views.py:349
|
|
225
229
|
msgid "User or token is invalid"
|
|
226
230
|
msgstr "L'utilisateur ou le token est invalide"
|
|
227
231
|
|
|
228
|
-
#: views/authentication_views.py:
|
|
232
|
+
#: views/authentication_views.py:456
|
|
229
233
|
msgid "OTP is already enabled"
|
|
230
234
|
msgstr "OTP est déjà activé"
|
|
231
235
|
|
|
232
|
-
#: views/authentication_views.py:
|
|
236
|
+
#: views/authentication_views.py:497 views/authentication_views.py:533
|
|
233
237
|
msgid "Invalid code"
|
|
234
238
|
msgstr "Code invalide"
|
|
235
239
|
|
|
236
|
-
#: views/authentication_views.py:
|
|
240
|
+
#: views/authentication_views.py:532
|
|
237
241
|
msgid "OTP disabled"
|
|
238
242
|
msgstr "OTP désactivé"
|
|
239
243
|
|
|
240
|
-
#: views/authentication_views.py:
|
|
244
|
+
#: views/authentication_views.py:792
|
|
241
245
|
msgid ""
|
|
242
246
|
"If the email address you entered is correct, you will receive an email from "
|
|
243
247
|
"us with instructions to reset your password."
|
|
@@ -246,7 +250,7 @@ msgstr ""
|
|
|
246
250
|
"un courrier électronique de notre part contenant des instructions pour "
|
|
247
251
|
"réinitialiser votre mot de passe."
|
|
248
252
|
|
|
249
|
-
#: views/authentication_views.py:
|
|
253
|
+
#: views/authentication_views.py:866
|
|
250
254
|
msgid "A new authentication code has been sent by email."
|
|
251
255
|
msgstr "Un nouveau code d'authentification a été envoyé par e-mail."
|
|
252
256
|
|
|
@@ -58,12 +58,10 @@ class JWTTokenDecodeMixin:
|
|
|
58
58
|
user.get_user_jwt_signature_key() + settings.PFX_SECRET_KEY,
|
|
59
59
|
options=dict(require=["exp"]),
|
|
60
60
|
algorithms="HS256")
|
|
61
|
-
if '
|
|
62
|
-
if otp_login:
|
|
63
|
-
return user, *decoded['otp_login']
|
|
61
|
+
if decoded.get('pfx_otp_login') and not otp_login:
|
|
64
62
|
raise jwt.InvalidTokenError(
|
|
65
63
|
"This token is reserved for OTP login")
|
|
66
|
-
return user
|
|
64
|
+
return user, *decoded.get('pfx_login_options', ['jwt', False])
|
|
67
65
|
except (get_user_model().DoesNotExist, jwt.ExpiredSignatureError,
|
|
68
66
|
jwt.InvalidTokenError, jwt.InvalidSignatureError,
|
|
69
67
|
DecodeError) as e:
|
|
@@ -93,7 +91,8 @@ class AuthenticationMiddleware(JWTTokenDecodeMixin, MiddlewareMixin):
|
|
|
93
91
|
except ValueError:
|
|
94
92
|
token = ""
|
|
95
93
|
try:
|
|
96
|
-
request.user =
|
|
94
|
+
request.user, request.login_mode, request.login_remember_me = (
|
|
95
|
+
self.decode_jwt(token))
|
|
97
96
|
except Exception:
|
|
98
97
|
request.user = AnonymousUser()
|
|
99
98
|
else:
|
|
@@ -122,7 +121,8 @@ class CookieAuthenticationMiddleware(JWTTokenDecodeMixin, MiddlewareMixin):
|
|
|
122
121
|
token = request.COOKIES.get('token', "")
|
|
123
122
|
if token:
|
|
124
123
|
try:
|
|
125
|
-
request.user =
|
|
124
|
+
request.user, request.login_mode, request.login_remember_me = (
|
|
125
|
+
self.decode_jwt(token))
|
|
126
126
|
except Exception:
|
|
127
127
|
request.user = AnonymousUser()
|
|
128
128
|
request.delete_cookie = True
|
|
@@ -69,10 +69,13 @@ class OtpUserMixin(models.Model):
|
|
|
69
69
|
"""Return the setup URL for OTP activation.
|
|
70
70
|
"""
|
|
71
71
|
import pyotp
|
|
72
|
+
args = dict(
|
|
73
|
+
name=self.get_username(), issuer_name=settings.PFX_SITE_NAME)
|
|
74
|
+
if settings.PFX_OTP_IMAGE:
|
|
75
|
+
args['image'] = settings.PFX_OTP_IMAGE
|
|
72
76
|
return pyotp.totp.TOTP(
|
|
73
77
|
tmp and self.otp_secret_token_tmp or
|
|
74
|
-
self.otp_secret_token).provisioning_uri(
|
|
75
|
-
name=self.email, issuer_name=settings.PFX_SITE_NAME)
|
|
78
|
+
self.otp_secret_token).provisioning_uri(**args)
|
|
76
79
|
|
|
77
80
|
def is_otp_valid(self, otp_code, tmp=False):
|
|
78
81
|
"""Verify an OTP code.
|
|
@@ -151,9 +151,9 @@ class AuthenticationView(
|
|
|
151
151
|
return self._login_need_otp_response(user, mode, remember_me)
|
|
152
152
|
return self._login_success(user, mode, remember_me)
|
|
153
153
|
|
|
154
|
-
def _login_success(
|
|
155
|
-
|
|
156
|
-
|
|
154
|
+
def _login_success(
|
|
155
|
+
self, user, mode, remember_me=False, message=None):
|
|
156
|
+
token = self._prepare_token(user, mode, remember_me)
|
|
157
157
|
if mode == 'cookie':
|
|
158
158
|
if remember_me:
|
|
159
159
|
expires = datetime.now(
|
|
@@ -170,6 +170,7 @@ class AuthenticationView(
|
|
|
170
170
|
httponly=True, samesite=settings.PFX_COOKIE_SAMESITE)
|
|
171
171
|
return res
|
|
172
172
|
return JsonResponse(dict(
|
|
173
|
+
message=message or _("Successful login"),
|
|
173
174
|
need_otp=False,
|
|
174
175
|
token=token,
|
|
175
176
|
user=self.get_user_information(user)))
|
|
@@ -178,8 +179,7 @@ class AuthenticationView(
|
|
|
178
179
|
"""Return the response for login if OTP login is needed.
|
|
179
180
|
|
|
180
181
|
Can be overridden to customize the response."""
|
|
181
|
-
token = self._prepare_token(user,
|
|
182
|
-
mode, remember_me])
|
|
182
|
+
token = self._prepare_token(user, mode, remember_me, otp_login=True)
|
|
183
183
|
return JsonResponse(dict(need_otp=True, token=token))
|
|
184
184
|
|
|
185
185
|
@method_decorator(never_cache)
|
|
@@ -252,10 +252,15 @@ class AuthenticationView(
|
|
|
252
252
|
return JsonResponse(
|
|
253
253
|
ValidationError(errors), status=422)
|
|
254
254
|
|
|
255
|
-
def _prepare_token(
|
|
256
|
-
|
|
255
|
+
def _prepare_token(
|
|
256
|
+
self, user, mode='jwt', remember_me=False, otp_login=False,
|
|
257
|
+
**extra_payload):
|
|
258
|
+
exp = datetime.now(tz=timezone.utc) + token_validity(
|
|
259
|
+
otp_login and 'otp' or (remember_me and 'long' or 'short'))
|
|
257
260
|
payload = dict(
|
|
258
261
|
exp=exp,
|
|
262
|
+
pfx_login_options=[mode, remember_me],
|
|
263
|
+
pfx_otp_login=otp_login,
|
|
259
264
|
**self.get_extra_payload(user), **extra_payload)
|
|
260
265
|
return jwt.encode(
|
|
261
266
|
payload,
|
|
@@ -486,7 +491,9 @@ class AuthenticationView(
|
|
|
486
491
|
raise NotFoundError()
|
|
487
492
|
data = self.deserialize_body()
|
|
488
493
|
if self.request.user.confirm_otp(data.get('otp_code')):
|
|
489
|
-
return
|
|
494
|
+
return self._login_success(
|
|
495
|
+
self.request.user, self.request.login_mode,
|
|
496
|
+
self.request.login_remember_me, message=_("OTP enabled"))
|
|
490
497
|
return JsonResponse(dict(otp_code=[_("Invalid code")]), status=422)
|
|
491
498
|
|
|
492
499
|
@method_decorator(never_cache)
|
|
@@ -520,7 +527,9 @@ class AuthenticationView(
|
|
|
520
527
|
data = self.deserialize_body()
|
|
521
528
|
if self.request.user.is_otp_valid(data.get('otp_code')):
|
|
522
529
|
self.request.user.disable_otp()
|
|
523
|
-
return
|
|
530
|
+
return self._login_success(
|
|
531
|
+
self.request.user, self.request.login_mode,
|
|
532
|
+
self.request.login_remember_me, message=_("OTP disabled"))
|
|
524
533
|
return JsonResponse(dict(otp_code=[_("Invalid code")]), status=422)
|
|
525
534
|
|
|
526
535
|
@method_decorator(never_cache)
|
|
@@ -894,6 +894,7 @@ class AuthAPITest(TestAssertMixin, TransactionTestCase):
|
|
|
894
894
|
self.assertRC(response, 200)
|
|
895
895
|
self.client.token = self.get_val(response, 'token')
|
|
896
896
|
|
|
897
|
+
@override_settings(PFX_OTP_IMAGE="https://example.org/fake.png")
|
|
897
898
|
def test_otp_enable(self):
|
|
898
899
|
self.client.login(username='jrr.tolkien', password='RIGHT PASSWORD')
|
|
899
900
|
|
|
@@ -901,7 +902,14 @@ class AuthAPITest(TestAssertMixin, TransactionTestCase):
|
|
|
901
902
|
response = self.client.get('/api/auth/otp/setup-uri')
|
|
902
903
|
self.assertRC(response, 200)
|
|
903
904
|
self.assertJIn(response, 'setup_uri', "otpauth://totp/")
|
|
905
|
+
self.assertJIn(response, 'setup_uri', "Books%20Demo:jrr.tolkien")
|
|
906
|
+
self.assertJIn(response, 'setup_uri', "issuer=Books%20Demo")
|
|
907
|
+
self.assertJIn(
|
|
908
|
+
response, 'setup_uri',
|
|
909
|
+
"image=https%3A%2F%2Fexample.org%2Ffake.png")
|
|
904
910
|
self.user1.refresh_from_db()
|
|
911
|
+
self.assertJIn(
|
|
912
|
+
response, 'setup_uri', f"secret={self.user1.otp_secret_token_tmp}")
|
|
905
913
|
self.assertIsNone(self.user1.otp_secret_token)
|
|
906
914
|
self.assertEqual(len(self.user1.otp_secret_token_tmp), 32)
|
|
907
915
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from datetime import timedelta
|
|
2
|
-
|
|
3
1
|
from django.core.exceptions import ImproperlyConfigured
|
|
4
2
|
from django.test import TestCase, override_settings
|
|
5
3
|
|
|
@@ -20,4 +18,4 @@ class TestSettings(TestAssertMixin, TestCase):
|
|
|
20
18
|
last_name='Test')
|
|
21
19
|
|
|
22
20
|
with self.assertRaises(ImproperlyConfigured):
|
|
23
|
-
AuthenticationView()._prepare_token(user
|
|
21
|
+
AuthenticationView()._prepare_token(user)
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/models/user_filtered_queryset_mixin.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/templates/registration/otp_code_email.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/templates/registration/welcome_email.txt
RENAMED
|
File without changes
|
{django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/templates/registration/welcome_subject.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/media_redirect.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/subset_page_size.py
RENAMED
|
File without changes
|
{django_pfx-1.4.dev42 → django_pfx-1.4.dev46}/pfx/pfxcore/views/parameters/subset_page_subset.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|