django-pfx 1.4.dev40__tar.gz → 1.4.dev44__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.dev40 → django_pfx-1.4.dev44}/PKG-INFO +1 -1
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/django_pfx.egg-info/PKG-INFO +1 -1
- django_pfx-1.4.dev44/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +20 -16
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/middleware/authentication.py +6 -6
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/models/login_ban.py +3 -1
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/authentication_views.py +18 -9
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_auth_api.py +18 -2
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_settings.py +1 -3
- django_pfx-1.4.dev40/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/.gitignore +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/.gitlab-ci.yml +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/.pre-commit-config.yaml +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/LICENSE +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/MANIFEST.in +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/README.md +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/django_pfx.egg-info/SOURCES.txt +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/django_pfx.egg-info/dependency_links.txt +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/django_pfx.egg-info/requires.txt +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/django_pfx.egg-info/top_level.txt +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/Makefile +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/conf.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/index.rst +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/source/api.views.rst +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/source/authentication.md +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/source/decorator.md +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/source/generate_openapi.md +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/source/getting_started.md +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/source/internationalisation.md +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/source/model.md +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/source/pfx_views.md +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/source/profiling.md +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/source/settings.md +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/doc/source/testing.md +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/img/pfx.png +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/img/pfx.svg +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/make_messages +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/manage.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/apidoc/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/apidoc/parameters.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/apidoc/schema.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/apidoc/tags.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/apps.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/decorator/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/decorator/rest.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/default_settings.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/exceptions.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/fields.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/http/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/http/json_response.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/management/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/management/commands/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/management/commands/makeapidoc.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/management/commands/profile.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/middleware/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/middleware/locale.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/middleware/profiling.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/migrations/0001_initial.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/migrations/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/models/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/models/cache_mixins.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/models/not_null_fields.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/models/otp_user_mixin.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/models/pfx_models.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/models/pfx_user.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/serializers/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/serializers/json.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/settings.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/shortcuts.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/storage/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/storage/s3_storage.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/test.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/urls.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/fields.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/filters_views.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/locale_views.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/date_format.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/groups.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/list_count.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/list_items.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/list_order.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/list_search.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/subset.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/rest_views.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/settings/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pfx/settings/dev.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/pyproject.toml +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/requirements.txt +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/serve-doc +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/setup.cfg +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/setup.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/models.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/settings/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/settings/ci.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/settings/common.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/settings/dev.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/settings/dev_custom_example.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/settings/dev_default.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/__init__.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/basic_api_errors.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/basic_api_test.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_api_doc.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_body_mixin.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_cache.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_client.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_fields.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_filters.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_locale_api.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_perm_tests.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_perms_api.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_profiling_middleware.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_shortcuts.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_timezone_middleware.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_tools.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_user_queryset.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_view_decorators.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/tests/test_view_fields.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/tests/urls.py +0 -0
- {django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/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"
|
|
@@ -59,23 +59,23 @@ msgstr ""
|
|
|
59
59
|
"Format non valide, il peut s’agir d’un nombre en heures, « 1:05 », « :05 », "
|
|
60
60
|
"« 1h 5m », « 1.5h » ou « 30m »."
|
|
61
61
|
|
|
62
|
-
#: models/login_ban.py:
|
|
62
|
+
#: models/login_ban.py:45
|
|
63
63
|
msgid "Username"
|
|
64
64
|
msgstr "Nom d’utilisateur"
|
|
65
65
|
|
|
66
|
-
#: models/login_ban.py:
|
|
66
|
+
#: models/login_ban.py:46
|
|
67
67
|
msgid "Failed counter"
|
|
68
68
|
msgstr "Compteur d’échec"
|
|
69
69
|
|
|
70
|
-
#: models/login_ban.py:
|
|
70
|
+
#: models/login_ban.py:47
|
|
71
71
|
msgid "Last failed"
|
|
72
72
|
msgstr "Dernier échec"
|
|
73
73
|
|
|
74
|
-
#: models/login_ban.py:
|
|
74
|
+
#: models/login_ban.py:52
|
|
75
75
|
msgid "Login ban"
|
|
76
76
|
msgstr "Login banni"
|
|
77
77
|
|
|
78
|
-
#: models/login_ban.py:
|
|
78
|
+
#: models/login_ban.py:53
|
|
79
79
|
msgid "Login bans"
|
|
80
80
|
msgstr "Login bannis"
|
|
81
81
|
|
|
@@ -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
|
|
@@ -17,7 +17,9 @@ class LoginBanQuerySet(models.QuerySet):
|
|
|
17
17
|
return False
|
|
18
18
|
if ban.failed_counter % settings.PFX_LOGIN_BAN_FAILED_NUMBER == 0:
|
|
19
19
|
seconds = settings.PFX_LOGIN_BAN_SECONDS_START + (
|
|
20
|
-
settings.PFX_LOGIN_BAN_SECONDS_STEP * (
|
|
20
|
+
settings.PFX_LOGIN_BAN_SECONDS_STEP * (
|
|
21
|
+
ban.failed_counter //
|
|
22
|
+
settings.PFX_LOGIN_BAN_FAILED_NUMBER - 1))
|
|
21
23
|
ban_time = ban.last_failed + timedelta(seconds=seconds)
|
|
22
24
|
now = timezone.now()
|
|
23
25
|
if now < ban_time:
|
|
@@ -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)
|
|
@@ -88,7 +88,7 @@ class AuthAPITest(TestAssertMixin, TransactionTestCase):
|
|
|
88
88
|
|
|
89
89
|
@override_settings(
|
|
90
90
|
PFX_TOKEN_SHORT_VALIDITY={'minutes': 30},
|
|
91
|
-
PFX_LOGIN_BAN_FAILED_NUMBER=
|
|
91
|
+
PFX_LOGIN_BAN_FAILED_NUMBER=2,
|
|
92
92
|
PFX_LOGIN_BAN_SECONDS_START=30,
|
|
93
93
|
PFX_LOGIN_BAN_SECONDS_STEP=60)
|
|
94
94
|
def test_login_ban(self):
|
|
@@ -98,6 +98,11 @@ class AuthAPITest(TestAssertMixin, TransactionTestCase):
|
|
|
98
98
|
'username': 'jrr.tolkien',
|
|
99
99
|
'password': 'BAD PASSWORD'})
|
|
100
100
|
self.assertRC(response, 422)
|
|
101
|
+
response = self.client.post(
|
|
102
|
+
'/api/auth/login', {
|
|
103
|
+
'username': 'jrr.tolkien',
|
|
104
|
+
'password': 'BAD PASSWORD'})
|
|
105
|
+
self.assertRC(response, 422)
|
|
101
106
|
|
|
102
107
|
response = self.client.post(
|
|
103
108
|
'/api/auth/login', {
|
|
@@ -128,6 +133,11 @@ class AuthAPITest(TestAssertMixin, TransactionTestCase):
|
|
|
128
133
|
'username': 'jrr.tolkien',
|
|
129
134
|
'password': 'BAD PASSWORD'})
|
|
130
135
|
self.assertRC(response, 422)
|
|
136
|
+
response = self.client.post(
|
|
137
|
+
'/api/auth/login', {
|
|
138
|
+
'username': 'jrr.tolkien',
|
|
139
|
+
'password': 'BAD PASSWORD'})
|
|
140
|
+
self.assertRC(response, 422)
|
|
131
141
|
|
|
132
142
|
response = self.client.post(
|
|
133
143
|
'/api/auth/login', {
|
|
@@ -1072,7 +1082,7 @@ class AuthAPITest(TestAssertMixin, TransactionTestCase):
|
|
|
1072
1082
|
|
|
1073
1083
|
@override_settings(
|
|
1074
1084
|
PFX_TOKEN_SHORT_VALIDITY={'minutes': 30},
|
|
1075
|
-
PFX_LOGIN_BAN_FAILED_NUMBER=
|
|
1085
|
+
PFX_LOGIN_BAN_FAILED_NUMBER=2,
|
|
1076
1086
|
PFX_LOGIN_BAN_SECONDS_START=30,
|
|
1077
1087
|
PFX_LOGIN_BAN_SECONDS_STEP=60)
|
|
1078
1088
|
def test_otp_login_ban(self):
|
|
@@ -1085,6 +1095,9 @@ class AuthAPITest(TestAssertMixin, TransactionTestCase):
|
|
|
1085
1095
|
self.assertRC(response, 200)
|
|
1086
1096
|
token = self.get_val(response, 'token')
|
|
1087
1097
|
|
|
1098
|
+
response = self.client.post('/api/auth/otp/login', dict(
|
|
1099
|
+
token=token, otp_code='-'))
|
|
1100
|
+
self.assertRC(response, 422)
|
|
1088
1101
|
response = self.client.post('/api/auth/otp/login', dict(
|
|
1089
1102
|
token=token, otp_code='-'))
|
|
1090
1103
|
self.assertRC(response, 422)
|
|
@@ -1112,6 +1125,9 @@ class AuthAPITest(TestAssertMixin, TransactionTestCase):
|
|
|
1112
1125
|
response = self.client.post('/api/auth/otp/login', dict(
|
|
1113
1126
|
token=token, otp_code='-'))
|
|
1114
1127
|
self.assertRC(response, 422)
|
|
1128
|
+
response = self.client.post('/api/auth/otp/login', dict(
|
|
1129
|
+
token=token, otp_code='-'))
|
|
1130
|
+
self.assertRC(response, 422)
|
|
1115
1131
|
|
|
1116
1132
|
response = self.client.post('/api/auth/otp/login', dict(
|
|
1117
1133
|
token=token, otp_code='-'))
|
|
@@ -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
|
|
File without changes
|
{django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/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.dev40 → django_pfx-1.4.dev44}/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.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/templates/registration/welcome_email.txt
RENAMED
|
File without changes
|
{django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/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.dev40 → django_pfx-1.4.dev44}/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.dev40 → django_pfx-1.4.dev44}/pfx/pfxcore/views/parameters/subset_page_size.py
RENAMED
|
File without changes
|
{django_pfx-1.4.dev40 → django_pfx-1.4.dev44}/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
|