django-hidp 2.0.0__tar.gz → 2.0.0.dev0__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.
Files changed (224) hide show
  1. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/PKG-INFO +8 -5
  2. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/email_change.py +34 -0
  3. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/email_verification.py +21 -2
  4. django_hidp-2.0.0.dev0/hidp/accounts/flows.py +129 -0
  5. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/mailers.py +62 -19
  6. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/views.py +53 -118
  7. django_hidp-2.0.0.dev0/hidp/api/auth_state.py +81 -0
  8. django_hidp-2.0.0.dev0/hidp/api/oidc_serializers.py +103 -0
  9. django_hidp-2.0.0.dev0/hidp/api/oidc_views.py +358 -0
  10. django_hidp-2.0.0.dev0/hidp/api/otp_serializers.py +54 -0
  11. django_hidp-2.0.0.dev0/hidp/api/otp_views.py +243 -0
  12. django_hidp-2.0.0.dev0/hidp/api/serializers.py +360 -0
  13. django_hidp-2.0.0.dev0/hidp/api/urls.py +116 -0
  14. django_hidp-2.0.0.dev0/hidp/api/user_urls.py +9 -0
  15. django_hidp-2.0.0.dev0/hidp/api/utils.py +62 -0
  16. django_hidp-2.0.0.dev0/hidp/api/views.py +585 -0
  17. django_hidp-2.0.0.dev0/hidp/config/checks.py +500 -0
  18. django_hidp-2.0.0.dev0/hidp/config/headless_urls.py +32 -0
  19. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/config/oauth2_provider.py +7 -1
  20. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/config/urls.py +5 -1
  21. django_hidp-2.0.0.dev0/hidp/constants.py +9 -0
  22. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/auth/backends.py +7 -0
  23. django_hidp-2.0.0.dev0/hidp/federated/flows.py +176 -0
  24. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/forms.py +10 -0
  25. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/providers/base.py +30 -0
  26. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/providers/microsoft.py +48 -0
  27. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/views.py +147 -91
  28. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/locale/django.pot +72 -14
  29. django_hidp-2.0.0.dev0/hidp/locale/nl/LC_MESSAGES/django.mo +0 -0
  30. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/locale/nl/LC_MESSAGES/django.po +73 -15
  31. django_hidp-2.0.0.dev0/hidp/oidc_provider/frontend.py +80 -0
  32. django_hidp-2.0.0.dev0/hidp/oidc_provider/views.py +66 -0
  33. django_hidp-2.0.0.dev0/hidp/otp/flows.py +31 -0
  34. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/otp/mailers.py +8 -5
  35. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/otp/middleware.py +80 -12
  36. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/otp/views.py +31 -22
  37. django_hidp-2.0.0.dev0/hidp/rate_limit/decorators.py +57 -0
  38. django_hidp-2.0.0.dev0/hidp/rate_limit/keys.py +21 -0
  39. django_hidp-2.0.0.dev0/hidp/rate_limit/middleware.py +18 -0
  40. django_hidp-2.0.0.dev0/hidp/rate_limit/views.py +24 -0
  41. django_hidp-2.0.0.dev0/hidp/utils.py +180 -0
  42. django_hidp-2.0.0.dev0/pyproject.toml +115 -0
  43. django_hidp-2.0.0/pyproject.toml → django_hidp-2.0.0.dev0/pyproject.toml.orig +21 -12
  44. django_hidp-2.0.0/hidp/api/serializers.py +0 -14
  45. django_hidp-2.0.0/hidp/api/urls.py +0 -14
  46. django_hidp-2.0.0/hidp/api/views.py +0 -26
  47. django_hidp-2.0.0/hidp/config/checks.py +0 -234
  48. django_hidp-2.0.0/hidp/locale/nl/LC_MESSAGES/django.mo +0 -0
  49. django_hidp-2.0.0/hidp/oidc_provider/views.py +0 -44
  50. django_hidp-2.0.0/hidp/rate_limit/decorators.py +0 -24
  51. django_hidp-2.0.0/hidp/rate_limit/middleware.py +0 -13
  52. django_hidp-2.0.0/hidp/rate_limit/views.py +0 -11
  53. django_hidp-2.0.0/hidp/utils.py +0 -91
  54. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/LICENSE +0 -0
  55. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/README.md +0 -0
  56. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/__init__.py +0 -0
  57. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/__init__.py +0 -0
  58. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/account_management_urls.py +0 -0
  59. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/account_urls.py +0 -0
  60. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/apps.py +0 -0
  61. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/auth.py +0 -0
  62. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/forms.py +0 -0
  63. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/management/__init__.py +0 -0
  64. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/management/commands/__init__.py +0 -0
  65. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/management/commands/remove_complete_and_stale_email_change_requests.py +0 -0
  66. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/management/commands/remove_stale_unverified_accounts.py +0 -0
  67. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/migrations/0001_initial.py +0 -0
  68. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/migrations/__init__.py +0 -0
  69. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/models.py +0 -0
  70. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/password_validation.py +0 -0
  71. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/accounts/tokens.py +0 -0
  72. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/api/__init__.py +0 -0
  73. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/api/apps.py +0 -0
  74. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/apps.py +0 -0
  75. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/compat/__init__.py +0 -0
  76. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/compat/uuid7.py +0 -0
  77. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/config/__init__.py +0 -0
  78. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/config/oidc_clients.py +0 -0
  79. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/csp/__init__.py +0 -0
  80. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/csp/decorators.py +0 -0
  81. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/csp/templatetags/__init__.py +0 -0
  82. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/csp/templatetags/csp_nonce.py +0 -0
  83. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/__init__.py +0 -0
  84. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/apps.py +0 -0
  85. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/auth/__init__.py +0 -0
  86. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/constants.py +0 -0
  87. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/management/__init__.py +0 -0
  88. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/management/commands/__init__.py +0 -0
  89. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/management/commands/refresh_oidc_clients_jwks.py +0 -0
  90. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/migrations/0001_initial.py +0 -0
  91. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/migrations/0002_openidconnection_last_usage.py +0 -0
  92. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/migrations/__init__.py +0 -0
  93. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/models.py +0 -0
  94. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/oidc/__init__.py +0 -0
  95. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/oidc/authorization_code_flow.py +0 -0
  96. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/oidc/exceptions.py +0 -0
  97. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/oidc/jwks.py +0 -0
  98. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/oidc_client_urls.py +0 -0
  99. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/oidc_management_urls.py +0 -0
  100. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/providers/__init__.py +0 -0
  101. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/providers/google.py +0 -0
  102. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/federated/tokens.py +0 -0
  103. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/oidc_provider/__init__.py +0 -0
  104. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/oidc_provider/apps.py +0 -0
  105. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/oidc_provider/middleware.py +0 -0
  106. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/oidc_provider/oauth_validators.py +0 -0
  107. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/oidc_provider/urls.py +0 -0
  108. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/otp/__init__.py +0 -0
  109. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/otp/decorators.py +0 -0
  110. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/otp/devices.py +0 -0
  111. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/otp/exceptions.py +0 -0
  112. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/otp/forms.py +0 -0
  113. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/otp/otp_management_urls.py +0 -0
  114. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/otp/otp_urls.py +0 -0
  115. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/rate_limit/__init__.py +0 -0
  116. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/forms/authentication_form.html +0 -0
  117. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/forms/rate_limited_authentication_form.html +0 -0
  118. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/forms/user_creation_form.html +0 -0
  119. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/login.html +0 -0
  120. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/logout_confirm.html +0 -0
  121. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/edit_account.html +0 -0
  122. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/edit_account_done.html +0 -0
  123. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email/email_change_body.html +0 -0
  124. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email/email_change_body.txt +0 -0
  125. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email/email_change_subject.txt +0 -0
  126. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email/email_changed_body.html +0 -0
  127. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email/email_changed_body.txt +0 -0
  128. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email/email_changed_subject.txt +0 -0
  129. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email/password_changed_body.html +0 -0
  130. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email/password_changed_body.txt +0 -0
  131. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email/password_changed_subject.txt +0 -0
  132. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email/proposed_email_exists_body.html +0 -0
  133. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email/proposed_email_exists_body.txt +0 -0
  134. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email/proposed_email_exists_subject.txt +0 -0
  135. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email_change_cancel.html +0 -0
  136. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email_change_cancel_done.html +0 -0
  137. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email_change_cancel_invalid_link.html +0 -0
  138. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email_change_complete.html +0 -0
  139. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email_change_confirm.html +0 -0
  140. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email_change_confirm_invalid_link.html +0 -0
  141. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email_change_request.html +0 -0
  142. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/email_change_request_sent.html +0 -0
  143. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/forms/edit_user_form.html +0 -0
  144. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/forms/email_change_cancel_form.html +0 -0
  145. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/forms/email_change_confirm_form.html +0 -0
  146. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/forms/email_change_request_form.html +0 -0
  147. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/forms/password_change_form.html +0 -0
  148. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/forms/set_password_form.html +0 -0
  149. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/manage_account.html +0 -0
  150. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/password_change.html +0 -0
  151. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/password_change_done.html +0 -0
  152. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/set_password.html +0 -0
  153. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/management/set_password_done.html +0 -0
  154. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/email/password_reset_body.html +0 -0
  155. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/email/password_reset_body.txt +0 -0
  156. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/email/password_reset_subject.txt +0 -0
  157. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/email/set_password_body.html +0 -0
  158. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/email/set_password_body.txt +0 -0
  159. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/email/set_password_subject.txt +0 -0
  160. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/forms/password_reset_form.html +0 -0
  161. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/forms/password_reset_request_form.html +0 -0
  162. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/password_reset.html +0 -0
  163. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/password_reset_complete.html +0 -0
  164. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/password_reset_email_sent.html +0 -0
  165. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/password_reset_invalid_link.html +0 -0
  166. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/recovery/password_reset_request.html +0 -0
  167. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/register.html +0 -0
  168. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/tos.html +0 -0
  169. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/verification/email/account_exists_body.html +0 -0
  170. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/verification/email/account_exists_body.txt +0 -0
  171. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/verification/email/account_exists_subject.txt +0 -0
  172. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/verification/email/verification_body.html +0 -0
  173. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/verification/email/verification_body.txt +0 -0
  174. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/verification/email/verification_subject.txt +0 -0
  175. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/verification/email_verification_complete.html +0 -0
  176. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/verification/email_verification_required.html +0 -0
  177. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/verification/email_verification_required_invalid_link.html +0 -0
  178. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/verification/forms/email_verification_form.html +0 -0
  179. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/verification/verify_email.html +0 -0
  180. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/accounts/verification/verify_email_invalid_link.html +0 -0
  181. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/base.html +0 -0
  182. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/base_email.html +0 -0
  183. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/base_invalid_link.html +0 -0
  184. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/base_post_login.html +0 -0
  185. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/base_pre_login.html +0 -0
  186. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/federated/account_link.html +0 -0
  187. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/federated/account_link_done.html +0 -0
  188. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/federated/account_unlink.html +0 -0
  189. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/federated/account_unlink_done.html +0 -0
  190. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/federated/forms/account_link_form.html +0 -0
  191. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/federated/forms/account_unlink_form.html +0 -0
  192. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/federated/forms/registration_form.html +0 -0
  193. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/federated/linked_services.html +0 -0
  194. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/federated/registration.html +0 -0
  195. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/includes/federated/oidc_provider_list.html +0 -0
  196. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/includes/federated/oidc_provider_list_option.html +0 -0
  197. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/includes/forms/base_form.html +0 -0
  198. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/includes/forms/logout_form.html +0 -0
  199. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/includes/forms/submit_row.html +0 -0
  200. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/disable.html +0 -0
  201. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/disable_recovery_code.html +0 -0
  202. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/email/configured_body.html +0 -0
  203. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/email/configured_body.txt +0 -0
  204. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/email/configured_subject.txt +0 -0
  205. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/email/disabled_body.html +0 -0
  206. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/email/disabled_body.txt +0 -0
  207. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/email/disabled_subject.txt +0 -0
  208. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/email/recovery_code_used_body.html +0 -0
  209. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/email/recovery_code_used_body.txt +0 -0
  210. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/email/recovery_code_used_subject.txt +0 -0
  211. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/email/recovery_codes_regenerated_body.html +0 -0
  212. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/email/recovery_codes_regenerated_body.txt +0 -0
  213. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/email/recovery_codes_regenerated_subject.txt +0 -0
  214. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/forms/otp_verify_form.html +0 -0
  215. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/overview.html +0 -0
  216. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/recovery_codes.html +0 -0
  217. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/setup_device.html +0 -0
  218. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/setup_device_done.html +0 -0
  219. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/verify.html +0 -0
  220. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/templates/hidp/otp/verify_recovery_code.html +0 -0
  221. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/test/__init__.py +0 -0
  222. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/test/factories/__init__.py +0 -0
  223. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/test/factories/otp_factories.py +0 -0
  224. {django_hidp-2.0.0 → django_hidp-2.0.0.dev0}/hidp/test/factories/user_factories.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-hidp
3
- Version: 2.0.0
3
+ Version: 2.0.0.dev0
4
4
  Summary: Full-featured authentication system for Django projects
5
5
  Author: Jaap Roes, Dennis Bunskoek, Ramon de Jezus, Thomas Kalverda, Wouter de Vries
6
6
  Author-email: Jaap Roes <jroes@leukeleu.nl>, Dennis Bunskoek <dbunskoek@leukeleu.nl>, Ramon de Jezus <rdejezus@leukeleu.nl>, Thomas Kalverda <tkalverda@leukeleu.nl>, Wouter de Vries <wdevries@leukeleu.nl>
@@ -11,13 +11,15 @@ Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Framework :: Django
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: Programming Language :: Python :: 3
14
- Requires-Dist: django>=4.2
14
+ Requires-Dist: django>=5.2
15
15
  Requires-Dist: django-ratelimit>=4.1.0,<5
16
16
  Requires-Dist: jwcrypto>=1.5,<2
17
17
  Requires-Dist: requests>=2.32,<3
18
- Requires-Dist: django-hidp[oidc-provider,otp] ; extra == 'all'
19
- Requires-Dist: django-oauth-toolkit>=3.0.1 ; extra == 'oidc-provider'
20
- Requires-Dist: djangorestframework>=3.15.2 ; extra == 'oidc-provider'
18
+ Requires-Dist: django-hidp[api,oidc-provider,otp] ; extra == 'all'
19
+ Requires-Dist: djangorestframework>=3.15.2 ; extra == 'api'
20
+ Requires-Dist: drf-spectacular>=0.28.0 ; extra == 'api'
21
+ Requires-Dist: django-hidp[api] ; extra == 'oidc-provider'
22
+ Requires-Dist: django-oauth-toolkit>=3.4.1 ; extra == 'oidc-provider'
21
23
  Requires-Dist: django-otp>=1.5.0 ; extra == 'otp'
22
24
  Requires-Dist: segno>=1.3.0 ; extra == 'otp'
23
25
  Requires-Dist: django-hidp[otp] ; extra == 'recommended'
@@ -27,6 +29,7 @@ Project-URL: Repository, https://github.com/leukeleu/django-hidp/
27
29
  Project-URL: Issues, https://github.com/leukeleu/django-hidp/issues
28
30
  Project-URL: Releasenotes, https://github.com/leukeleu/django-hidp/releases
29
31
  Provides-Extra: all
32
+ Provides-Extra: api
30
33
  Provides-Extra: oidc-provider
31
34
  Provides-Extra: otp
32
35
  Provides-Extra: recommended
@@ -42,3 +42,37 @@ def remove_complete_and_stale_email_change_requests(*, days=7, dry_run=False):
42
42
  complete_and_stale_email_change_requests.delete()
43
43
 
44
44
  return complete_and_stale_email_change_requests_count
45
+
46
+
47
+ def get_pending_email_change_request(user, *, token_generator):
48
+ """Return the unexpired email change request of `user` that is not yet complete."""
49
+ return (
50
+ EmailChangeRequest.objects.filter(
51
+ user=user,
52
+ created_at__gte=(
53
+ timezone.now() - timedelta(seconds=token_generator.token_timeout)
54
+ ),
55
+ )
56
+ .exclude(confirmed_by_current_email=True, confirmed_by_proposed_email=True)
57
+ .first()
58
+ )
59
+
60
+
61
+ def get_email_change_request_from_token_data(user, token_data):
62
+ """
63
+ Return the email change request of `user` that `token_data` confirms.
64
+
65
+ Returns `None` when the token is malformed, or the request is already confirmed
66
+ for the recipient of the token.
67
+ """
68
+ if (
69
+ not isinstance(token_data, dict)
70
+ or set(token_data) != {"recipient", "uuid"}
71
+ or token_data["recipient"] not in set(Recipient)
72
+ ):
73
+ return None
74
+ return (
75
+ EmailChangeRequest.objects.filter(id=token_data["uuid"], user=user)
76
+ .exclude(**{f"confirmed_by_{token_data['recipient']}": True})
77
+ .first()
78
+ )
@@ -2,6 +2,7 @@ from datetime import timedelta
2
2
  from urllib.parse import urlencode
3
3
 
4
4
  from django.contrib.auth import get_user_model
5
+ from django.db.models.functions import MD5
5
6
  from django.urls import reverse
6
7
  from django.utils import timezone
7
8
 
@@ -22,11 +23,11 @@ def get_email_verification_required_url(user, *, next_url=""):
22
23
  return url
23
24
 
24
25
 
25
- def get_verify_email_url(user, *, next_url=""):
26
+ def get_verify_email_url(token, *, next_url=""):
26
27
  url = reverse(
27
28
  "hidp_accounts:verify_email",
28
29
  kwargs={
29
- "token": tokens.email_verification_token_generator.make_token(user),
30
+ "token": token,
30
31
  },
31
32
  )
32
33
  if next_url:
@@ -34,6 +35,24 @@ def get_verify_email_url(user, *, next_url=""):
34
35
  return url
35
36
 
36
37
 
38
+ def get_unverified_user_from_token(token, *, token_generator):
39
+ """
40
+ Return the active, unverified user identified by an email verification token.
41
+
42
+ Returns `None` if the token is invalid or expired, or if no such user exists.
43
+ """
44
+ email_hash = token_generator.check_token(token) if token else None
45
+ if email_hash is None:
46
+ return None
47
+ return (
48
+ UserModel.objects.email_unverified()
49
+ .filter(is_active=True)
50
+ .annotate(email_hash=MD5("email"))
51
+ .filter(email_hash=email_hash)
52
+ .first()
53
+ )
54
+
55
+
37
56
  def remove_stale_unverified_accounts(*, days=90, dry_run=False):
38
57
  """
39
58
  Remove accounts that are not verified within a given number of days after creation.
@@ -0,0 +1,129 @@
1
+ """Account side effects shared by the HTML views and the API."""
2
+
3
+ import logging
4
+
5
+ from datetime import timedelta
6
+
7
+ from django.contrib.auth import get_user_model, update_session_auth_hash
8
+ from django.db import IntegrityError, transaction
9
+ from django.utils import timezone
10
+
11
+ from . import auth as hidp_auth
12
+ from .email_change import Recipient
13
+
14
+ logger = logging.getLogger(__name__)
15
+ UserModel = get_user_model()
16
+
17
+ REAUTHENTICATION_DELTA = timedelta(minutes=5)
18
+
19
+
20
+ def register(form):
21
+ """
22
+ Save the user of a valid `UserCreationForm`.
23
+
24
+ Returns the existing user when the email address is taken, so the caller can
25
+ respond the same way whether or not an account exists.
26
+ """
27
+ try:
28
+ with transaction.atomic():
29
+ return form.save()
30
+ except IntegrityError:
31
+ return UserModel.objects.get(email__iexact=form.cleaned_data["email"])
32
+
33
+
34
+ def send_registration_email(user, *, verification_mailer, account_exists_mailer):
35
+ """Send the verification email, or tell an existing user they have an account."""
36
+ try:
37
+ if not user.email_verified:
38
+ verification_mailer(user).send()
39
+ elif user.is_active:
40
+ account_exists_mailer(user).send()
41
+ except Exception:
42
+ # Do not leak the existence of the user.
43
+ logger.exception("Failed to send verification email.")
44
+
45
+
46
+ def send_verification_email(user, *, verification_mailer):
47
+ """
48
+ Send the email verification email, logging a failure instead of raising it.
49
+
50
+ A failed send must not fail the request of a user who is waiting for the
51
+ email, such as a login with valid credentials.
52
+ """
53
+ try:
54
+ verification_mailer(user).send()
55
+ except Exception:
56
+ logger.exception("Failed to send verification email.")
57
+
58
+
59
+ def login(request, user):
60
+ """Log in a user with a verified email address, and return whether it did."""
61
+ if user.email_verified:
62
+ hidp_auth.login(request, user)
63
+ return True
64
+ return False
65
+
66
+
67
+ def send_password_reset_email(user, *, password_reset_mailer, set_password_mailer):
68
+ """Send a password reset link, or a set password link to a user without one."""
69
+ mailer = (
70
+ password_reset_mailer if user.has_usable_password() else set_password_mailer
71
+ )
72
+ try:
73
+ mailer(user).send()
74
+ except Exception:
75
+ # Do not leak the existence of the user.
76
+ logger.exception("Failed to send password (re)set email.")
77
+
78
+
79
+ def change_password(request, form):
80
+ """Save the new password of a valid password form, keeping the session valid."""
81
+ user = form.save()
82
+ update_session_auth_hash(request, user)
83
+ return user
84
+
85
+
86
+ def requires_reauthentication(user, *, delta=REAUTHENTICATION_DELTA):
87
+ """Whether `user` must log in again before setting a password."""
88
+ return user.last_login is None or user.last_login < timezone.now() - delta
89
+
90
+
91
+ def send_email_change_emails(
92
+ user,
93
+ email_change_request,
94
+ *,
95
+ email_change_request_mailer,
96
+ proposed_email_exists_mailer,
97
+ ):
98
+ """
99
+ Ask the current and proposed email addresses to confirm the change.
100
+
101
+ An existing account at the proposed address is told so, unless it is inactive.
102
+ """
103
+ email_change_request_mailer(
104
+ user,
105
+ email_change_request=email_change_request,
106
+ recipient=Recipient.CURRENT_EMAIL,
107
+ ).send()
108
+
109
+ existing_user = UserModel.objects.filter(
110
+ email__iexact=email_change_request.proposed_email
111
+ ).first()
112
+ if existing_user and not existing_user.is_active:
113
+ return
114
+ mailer = (
115
+ proposed_email_exists_mailer if existing_user else email_change_request_mailer
116
+ )
117
+ mailer(
118
+ user,
119
+ email_change_request=email_change_request,
120
+ recipient=Recipient.PROPOSED_EMAIL,
121
+ ).send()
122
+
123
+
124
+ def confirm_email_change(form):
125
+ """Save a valid `EmailChangeConfirmForm`, or return `None` if the email is taken."""
126
+ try:
127
+ return form.save()
128
+ except IntegrityError:
129
+ return None
@@ -7,6 +7,7 @@ from django.urls import reverse
7
7
  from django.utils.encoding import force_bytes
8
8
  from django.utils.http import urlsafe_base64_encode
9
9
 
10
+ from ..utils import add_query_params
10
11
  from . import email_verification, tokens
11
12
  from .email_change import Recipient
12
13
 
@@ -93,16 +94,27 @@ class EmailVerificationMailer(BaseMailer):
93
94
  email_template_name = "hidp/accounts/verification/email/verification_body.txt"
94
95
  html_email_template_name = "hidp/accounts/verification/email/verification_body.html"
95
96
 
96
- def __init__(self, user, *, base_url, post_verification_redirect=None):
97
+ def __init__(
98
+ self, user, *, base_url, post_verification_redirect=None, verification_url=None
99
+ ):
97
100
  super().__init__(base_url=base_url)
98
101
  self.user = user
99
102
  self.post_verification_redirect = post_verification_redirect
103
+ self.verification_url = verification_url
100
104
 
101
105
  def get_verification_url(self):
106
+ token = tokens.email_verification_token_generator.make_token(self.user)
107
+
108
+ if self.verification_url:
109
+ return add_query_params(
110
+ self.verification_url.format(token=token),
111
+ next=self.post_verification_redirect or None,
112
+ )
113
+
102
114
  return urljoin(
103
115
  self.base_url,
104
116
  email_verification.get_verify_email_url(
105
- self.user,
117
+ token=token,
106
118
  next_url=self.post_verification_redirect,
107
119
  ),
108
120
  )
@@ -129,12 +141,15 @@ class AccountExistsMailer(BaseMailer):
129
141
  "hidp/accounts/verification/email/account_exists_body.html"
130
142
  )
131
143
 
132
- def __init__(self, user, *, base_url):
144
+ def __init__(self, user, *, base_url, password_reset_url=None):
133
145
  super().__init__(base_url=base_url)
134
146
  self.user = user
147
+ self.password_reset_url = password_reset_url
135
148
 
136
149
  def get_password_reset_url(self):
137
- return urljoin(self.base_url, reverse("hidp_accounts:password_reset_request"))
150
+ return self.password_reset_url or urljoin(
151
+ self.base_url, reverse("hidp_accounts:password_reset_request")
152
+ )
138
153
 
139
154
  def get_context(self, extra_context=None):
140
155
  return super().get_context(
@@ -155,9 +170,10 @@ class PasswordResetRequestMailer(BaseMailer):
155
170
  html_email_template_name = "hidp/accounts/recovery/email/password_reset_body.html"
156
171
  token_generator = default_token_generator
157
172
 
158
- def __init__(self, user, *, base_url):
173
+ def __init__(self, user, *, base_url, password_reset_url=None):
159
174
  super().__init__(base_url=base_url)
160
175
  self.user = user
176
+ self.password_reset_url = password_reset_url
161
177
 
162
178
  def get_password_reset_url(self):
163
179
  """
@@ -166,13 +182,19 @@ class PasswordResetRequestMailer(BaseMailer):
166
182
  Returns:
167
183
  An absolute URL to the password reset page for the given user.
168
184
  """
185
+ uidb64 = urlsafe_base64_encode(force_bytes(self.user.pk))
186
+ token = self.token_generator.make_token(self.user)
187
+
188
+ if self.password_reset_url:
189
+ return self.password_reset_url.format(uidb64=uidb64, token=token)
190
+
169
191
  return urljoin(
170
192
  self.base_url,
171
193
  reverse(
172
194
  "hidp_accounts:password_reset",
173
195
  kwargs={
174
- "uidb64": urlsafe_base64_encode(force_bytes(self.user.pk)),
175
- "token": self.token_generator.make_token(self.user),
196
+ "uidb64": uidb64,
197
+ "token": token,
176
198
  },
177
199
  ),
178
200
  )
@@ -198,12 +220,15 @@ class SetPasswordMailer(BaseMailer):
198
220
  email_template_name = "hidp/accounts/recovery/email/set_password_body.txt"
199
221
  html_email_template_name = "hidp/accounts/recovery/email/set_password_body.html"
200
222
 
201
- def __init__(self, user, *, base_url):
223
+ def __init__(self, user, *, base_url, set_password_url=None):
202
224
  super().__init__(base_url=base_url)
203
225
  self.user = user
226
+ self.set_password_url = set_password_url
204
227
 
205
228
  def get_set_password_url(self):
206
- return urljoin(self.base_url, reverse("hidp_account_management:set_password"))
229
+ return self.set_password_url or urljoin(
230
+ self.base_url, reverse("hidp_account_management:set_password")
231
+ )
207
232
 
208
233
  def get_context(self, extra_context=None):
209
234
  return super().get_context(
@@ -227,12 +252,15 @@ class PasswordChangedMailer(BaseMailer):
227
252
  "hidp/accounts/management/email/password_changed_body.html"
228
253
  )
229
254
 
230
- def __init__(self, user, *, base_url):
255
+ def __init__(self, user, *, base_url, password_reset_url=None):
231
256
  super().__init__(base_url=base_url)
232
257
  self.user = user
258
+ self.password_reset_url = password_reset_url
233
259
 
234
260
  def get_password_reset_url(self):
235
- return urljoin(self.base_url, reverse("hidp_accounts:password_reset_request"))
261
+ return self.password_reset_url or urljoin(
262
+ self.base_url, reverse("hidp_accounts:password_reset_request")
263
+ )
236
264
 
237
265
  def get_context(self, extra_context=None):
238
266
  return super().get_context(
@@ -252,28 +280,43 @@ class EmailChangeRequestMailer(BaseMailer):
252
280
  email_template_name = "hidp/accounts/management/email/email_change_body.txt"
253
281
  html_email_template_name = "hidp/accounts/management/email/email_change_body.html"
254
282
 
255
- def __init__(self, user, *, base_url, email_change_request, recipient):
283
+ def __init__(
284
+ self,
285
+ user,
286
+ *,
287
+ base_url,
288
+ email_change_request,
289
+ recipient,
290
+ confirmation_url=None,
291
+ cancel_url=None,
292
+ ):
256
293
  super().__init__(base_url=base_url)
257
294
  self.user = user
258
295
  self.email_change_request = email_change_request
259
296
  self.recipient = recipient
297
+ self.confirmation_url = confirmation_url
298
+ self.cancel_url = cancel_url
260
299
 
261
300
  def get_confirmation_url(self):
301
+ token = tokens.email_change_token_generator.make_token(
302
+ str(self.email_change_request.pk), self.recipient
303
+ )
304
+
305
+ if self.confirmation_url:
306
+ return self.confirmation_url.format(token=token)
307
+
262
308
  return urljoin(
263
309
  self.base_url,
264
310
  reverse(
265
311
  "hidp_account_management:email_change_confirm",
266
- kwargs={
267
- "token": (
268
- tokens.email_change_token_generator.make_token(
269
- str(self.email_change_request.pk), self.recipient
270
- )
271
- )
272
- },
312
+ kwargs={"token": token},
273
313
  ),
274
314
  )
275
315
 
276
316
  def get_cancel_url(self):
317
+ if self.cancel_url:
318
+ return self.cancel_url
319
+
277
320
  return urljoin(
278
321
  self.base_url,
279
322
  reverse("hidp_account_management:email_change_cancel"),