diff --git a/README.md b/README.md index ef4791c..c31c3a7 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ defaults for new projects. - ๐Ÿ“ฑ Mobile-friendly design - ๐Ÿ’„ Configurable themes +- ๐Ÿ•ต๏ธ Support for []allauth user sessions](https://docs.allauth.org/en/latest/usersessions/index.html) +- ๐Ÿ“ฑSupport for [Multi-Factor Authentication](https://docs.allauth.org/en/latest/mfa/index.html) - ๐Ÿ—ฃ๏ธ Translations - ๐Ÿ‡ช๐Ÿ‡ธ Spanish - ๐Ÿ‡ซ๐Ÿ‡ท French diff --git a/allauth_ui/templates/allauth/layouts/base.html b/allauth_ui/templates/allauth/layouts/base.html index 6ef19aa..61331ae 100644 --- a/allauth_ui/templates/allauth/layouts/base.html +++ b/allauth_ui/templates/allauth/layouts/base.html @@ -1,3 +1,4 @@ +{# djlint:off H006 #} {% load i18n %} {% load static %} {% load allauth_ui %} diff --git a/allauth_ui/templates/components/form.html b/allauth_ui/templates/components/form.html index 3b0c93e..3997aab 100644 --- a/allauth_ui/templates/components/form.html +++ b/allauth_ui/templates/components/form.html @@ -1,4 +1,6 @@ -{% load widget_tweaks slippers %} +{% load slippers %} +{% load allauth_ui %} +{% load widget_tweaks %} {% var render_fields=render_fields|default:"true" %} {% var use_default_button=use_default_button|default:"true" %}
@@ -8,17 +10,8 @@ {% if render_fields == "true" %} {% for field in form.visible_fields %} {% if field.name != "remember" %} - - {% if field.errors %} - {% render_field field placeholder="" class="w-full input input-bordered text-primary input-error" %} - {% else %} - {% render_field field placeholder="" class="w-full input input-bordered text-primary" %} - {% endif %} - {% for error in field.errors %} - {{ error }} - {% endfor %} + {% #form_field field=field %} + {% /form_field %} {% endif %} {% endfor %} {% endif %} diff --git a/allauth_ui/templates/components/form_field.html b/allauth_ui/templates/components/form_field.html new file mode 100644 index 0000000..bedd6a7 --- /dev/null +++ b/allauth_ui/templates/components/form_field.html @@ -0,0 +1,12 @@ +{% load widget_tweaks %} + +{% if field.errors %} + {% render_field field placeholder="" class="w-full input input-bordered text-primary input-error" %} +{% else %} + {% render_field field placeholder="" class="w-full input input-bordered text-primary" %} +{% endif %} +{% for error in field.errors %} + {{ error }} +{% endfor %} diff --git a/allauth_ui/templates/mfa/index.html b/allauth_ui/templates/mfa/index.html new file mode 100644 index 0000000..c08fa63 --- /dev/null +++ b/allauth_ui/templates/mfa/index.html @@ -0,0 +1,73 @@ +{% extends "mfa/index.html" %} +{% load i18n %} +{% load allauth_ui %} +{% block content %} + {% trans "Two-Factor Authentication" as heading %} + {% #container heading=heading %} + {% if "totp" in MFA_SUPPORTED_TYPES %} +

{% translate "Authenticator App" %}

+ {% if authenticators.totp %} +

+ {% translate "Authentication using an authenticator app is active." %} +

+ {% translate "Deactivate" %} +
+

+ {% else %} +

{% translate "An authenticator app is not active." %}

+ {% translate "Activate" %} + {% endif %} + {% endif %} + {% if "webauthn" in MFA_SUPPORTED_TYPES %} +
+

{% translate "Security Keys" %}

+ {% if authenticators.webauthn|length %} +

+ {% blocktranslate count count=authenticators.webauthn|length %}You have added {{ count }} security key.{% plural %}You have added {{ count }} security keys.{% endblocktranslate %} +

+ {% translate "Manage" %} + {% else %} +

{% translate "No security keys have been added." %}

+ {% translate "Add" %} + {% endif %} + {% endif %} + {% if "recovery_codes" in MFA_SUPPORTED_TYPES %} +
+ {% with total_count=authenticators.recovery_codes.generate_codes|length unused_count=authenticators.recovery_codes.get_unused_codes|length %} +

{% translate "Recovery Codes" %}

+

+ {% if authenticators.recovery_codes %} + {% blocktranslate count unused_count=unused_count %}There is {{ unused_count }} out of {{ total_count }} recovery codes available.{% plural %}There are {{ unused_count }} out of {{ total_count }} recovery codes available.{% endblocktranslate %} + {% else %} + {% translate "No recovery codes set up." %} + {% endif %} +

+ {% if is_mfa_enabled %} +
+ {% if authenticators.recovery_codes %} + {% if unused_count > 0 %} + {% translate "View" %} + {% translate "Download" %} + {% endif %} + {% endif %} + {% translate "Generate" %} +
+ {% endif %} + {% endwith %} + {% endif %} + {% /container %} +{% endblock content %} diff --git a/allauth_ui/templates/mfa/recovery_codes/generate.html b/allauth_ui/templates/mfa/recovery_codes/generate.html new file mode 100644 index 0000000..e577c8e --- /dev/null +++ b/allauth_ui/templates/mfa/recovery_codes/generate.html @@ -0,0 +1,21 @@ +{% extends "mfa/recovery_codes/index.html" %} +{% load i18n %} +{% load allauth %} +{% load allauth_ui %} +{% block content %} + {% translate "Recovery Codes" as heading %} + {% blocktranslate asvar subheading %}You are about to generate a new set of recovery codes for your account.{% endblocktranslate %} + {% #container heading=heading subheading=subheading %} +

+ {% if unused_code_count %} + {% blocktranslate %}This action will invalidate your existing codes.{% endblocktranslate %} + {% endif %} + {% blocktranslate %}Are you sure?{% endblocktranslate %} +

+ {% url 'mfa_generate_recovery_codes' as action_url %} + {% trans "Generate" as button_text %} + {% #form url=action_url form=form button_text=button_text %} + {% csrf_token %} + {% /form %} + {% /container %} +{% endblock content %} diff --git a/allauth_ui/templates/mfa/recovery_codes/index.html b/allauth_ui/templates/mfa/recovery_codes/index.html new file mode 100644 index 0000000..75dbac6 --- /dev/null +++ b/allauth_ui/templates/mfa/recovery_codes/index.html @@ -0,0 +1,27 @@ +{% extends "mfa/recovery_codes/index.html" %} +{% load i18n %} +{% load allauth %} +{% load allauth_ui %} +{% block content %} + {% translate "Recovery Codes" as heading %} + {% blocktranslate asvar subheading count unused_count=unused_codes|length %}There is {{ unused_count }} out of {{ total_count }} recovery codes available.{% plural %}There are {{ unused_count }} out of {{ total_count }} recovery codes available.{% endblocktranslate %} + {% #container heading=heading subheading=subheading %} +
+ + +
+
+ {% if unused_codes %} + {% trans "Download codes" %} + {% endif %} + {% trans "Generate new codes" %} +
+ {% /container %} +{% endblock content %} diff --git a/allauth_ui/templates/mfa/totp/activate_form.html b/allauth_ui/templates/mfa/totp/activate_form.html new file mode 100644 index 0000000..1bc78a8 --- /dev/null +++ b/allauth_ui/templates/mfa/totp/activate_form.html @@ -0,0 +1,31 @@ +{# djlint:off H006 #} +{% extends "mfa/totp/activate_form.html" %} +{% load allauth %} +{% load allauth_ui %} +{% load i18n %} +{% block content %} + {% translate "Activate Authenticator App" as heading %} + {% blocktranslate asvar subheading %}To protect your account with two-factor authentication, scan the QR code below with your authenticator app. Then, input the verification code generated by the app below.{% endblocktranslate %} + {% #container heading=heading subheading=subheading %} + {% translate "Activate" as button_text %} + {% url 'mfa_activate_totp' as action_url %} + {% #form form=form method="post" url=action_url button_text=button_text render_fields="false" %} + {{ form.secret }} + {% #form_field field=form.code %} + {% /form_field %} +
+ +

+ {% translate "You can store this secret and use it to reinstall your authenticator app at a later time." %} +

+ +
+ {% csrf_token %} + {% /form %} + {% /container %} + {% endblock content %} diff --git a/allauth_ui/templates/mfa/totp/deactivate_form.html b/allauth_ui/templates/mfa/totp/deactivate_form.html new file mode 100644 index 0000000..f112596 --- /dev/null +++ b/allauth_ui/templates/mfa/totp/deactivate_form.html @@ -0,0 +1,14 @@ +{% extends "mfa/totp/deactivate_form.html" %} +{% load i18n %} +{% load allauth_ui %} +{% block content %} + {% trans "Deactivate Authenticator App" as heading %} + {% blocktranslate asvar subheading %}You are about to deactivate authenticator app based authentication. Are you sure?{% endblocktranslate %} + {% #container heading=heading subheading=subheading %} + {% url 'mfa_deactivate_totp' as action_url %} + {% #form form=form url=action_url button_text=button_text use_default_button="false"%} + {% csrf_token %} + + {% /form %} + {% /container %} +{% endblock content %} diff --git a/allauth_ui/templates/usersessions/usersession_list.html b/allauth_ui/templates/usersessions/usersession_list.html index bb22100..001d5c9 100644 --- a/allauth_ui/templates/usersessions/usersession_list.html +++ b/allauth_ui/templates/usersessions/usersession_list.html @@ -9,7 +9,7 @@

{{ heading }}

{% if session_count > 1 %} {% url 'usersessions_list' as action_url %} - {% translate "Sign Out Other Sessions" as button_text %} + {% translate "Sign Out Other Sessions" as button_text %} {% else %} {% url 'account_logout' as action_url %} {% translate "Sign Out" as button_text %} diff --git a/allauth_ui/templatetags/allauth_ui.py b/allauth_ui/templatetags/allauth_ui.py index 61f00e2..049b11b 100644 --- a/allauth_ui/templatetags/allauth_ui.py +++ b/allauth_ui/templatetags/allauth_ui.py @@ -14,6 +14,7 @@ def allauth_ui_theme(): { "container": "components/container.html", "form": "components/form.html", + "form_field": "components/form_field.html", }, register, ) diff --git a/poetry.lock b/poetry.lock index 54a610a..8225032 100644 --- a/poetry.lock +++ b/poetry.lock @@ -110,6 +110,17 @@ files = [ [package.dependencies] frozenlist = ">=1.1.0" +[[package]] +name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = "*" +files = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] + [[package]] name = "appnope" version = "0.1.4" @@ -300,6 +311,70 @@ files = [ {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] +[[package]] +name = "cffi" +version = "1.16.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, +] + +[package.dependencies] +pycparser = "*" + [[package]] name = "charset-normalizer" version = "3.3.2" @@ -488,6 +563,55 @@ files = [ [package.extras] toml = ["tomli"] +[[package]] +name = "cryptography" +version = "43.0.0" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cryptography-43.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74"}, + {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895"}, + {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22"}, + {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47"}, + {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf"}, + {file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55"}, + {file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431"}, + {file = "cryptography-43.0.0-cp37-abi3-win32.whl", hash = "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc"}, + {file = "cryptography-43.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778"}, + {file = "cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66"}, + {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5"}, + {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e"}, + {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5"}, + {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f"}, + {file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0"}, + {file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b"}, + {file = "cryptography-43.0.0-cp39-abi3-win32.whl", hash = "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf"}, + {file = "cryptography-43.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709"}, + {file = "cryptography-43.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c6d112bf61c5ef44042c253e4859b3cbbb50df2f78fa8fae6747a7814484a70"}, + {file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:844b6d608374e7d08f4f6e6f9f7b951f9256db41421917dfb2d003dde4cd6b66"}, + {file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51956cf8730665e2bdf8ddb8da0056f699c1a5715648c1b0144670c1ba00b48f"}, + {file = "cryptography-43.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:aae4d918f6b180a8ab8bf6511a419473d107df4dbb4225c7b48c5c9602c38c7f"}, + {file = "cryptography-43.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:232ce02943a579095a339ac4b390fbbe97f5b5d5d107f8a08260ea2768be8cc2"}, + {file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5bcb8a5620008a8034d39bce21dc3e23735dfdb6a33a06974739bfa04f853947"}, + {file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:08a24a7070b2b6804c1940ff0f910ff728932a9d0e80e7814234269f9d46d069"}, + {file = "cryptography-43.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e9c5266c432a1e23738d178e51c2c7a5e2ddf790f248be939448c0ba2021f9d1"}, + {file = "cryptography-43.0.0.tar.gz", hash = "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e"}, +] + +[package.dependencies] +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] +docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] +nox = ["nox"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi", "cryptography-vectors (==43.0.0)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + [[package]] name = "cssbeautifier" version = "1.15.1" @@ -552,19 +676,21 @@ bcrypt = ["bcrypt"] [[package]] name = "django-allauth" -version = "0.63.6" +version = "64.0.0" description = "Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "django_allauth-0.63.6.tar.gz", hash = "sha256:f15f49defb09e0604dad5214e53a69a1f723cb03176bb115c8930bcd19b91749"}, + {file = "django_allauth-64.0.0.tar.gz", hash = "sha256:01952c7540160ef475c12dc881f67a69c7c5e533f4bef6c811bba0417a717588"}, ] [package.dependencies] -Django = ">=3.2" +Django = ">=4.2" +fido2 = {version = ">=1.1.2", optional = true, markers = "extra == \"mfa\""} +qrcode = {version = ">=7.0.0", optional = true, markers = "extra == \"mfa\""} [package.extras] -mfa = ["qrcode (>=7.0.0)"] +mfa = ["fido2 (>=1.1.2)", "qrcode (>=7.0.0)"] openid = ["python3-openid (>=3.0.8)"] saml = ["python3-saml (>=1.15.0,<2.0.0)"] socialaccount = ["pyjwt[crypto] (>=1.7)", "requests (>=2.0.0)", "requests-oauthlib (>=0.3.0)"] @@ -694,16 +820,6 @@ regex = ">=2023.0.0,<2024.0.0" tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} tqdm = ">=4.62.2,<5.0.0" -[[package]] -name = "docopt" -version = "0.6.2" -description = "Pythonic argument parser, that will make you smile" -optional = false -python-versions = "*" -files = [ - {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, -] - [[package]] name = "editorconfig" version = "0.12.4" @@ -742,6 +858,23 @@ files = [ [package.extras] tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] +[[package]] +name = "fido2" +version = "1.1.3" +description = "FIDO2/WebAuthn library for implementing clients and servers." +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "fido2-1.1.3-py3-none-any.whl", hash = "sha256:6be34c0b9fe85e4911fd2d103cce7ae8ce2f064384a7a2a3bd970b3ef7702931"}, + {file = "fido2-1.1.3.tar.gz", hash = "sha256:26100f226d12ced621ca6198528ce17edf67b78df4287aee1285fee3cd5aa9fc"}, +] + +[package.dependencies] +cryptography = ">=2.6,<35 || >35,<45" + +[package.extras] +pcsc = ["pyscard (>=1.9,<3)"] + [[package]] name = "frozenlist" version = "1.4.1" @@ -1326,18 +1459,16 @@ files = [ [[package]] name = "prompt-toolkit" -version = "2.0.10" +version = "3.0.47" description = "Library for building powerful interactive command lines in Python" optional = false -python-versions = ">=2.6,<3.0.dev0 || >=3.3.dev0" +python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-2.0.10-py2-none-any.whl", hash = "sha256:e7f8af9e3d70f514373bf41aa51bc33af12a6db3f71461ea47fea985defb2c31"}, - {file = "prompt_toolkit-2.0.10-py3-none-any.whl", hash = "sha256:46642344ce457641f28fc9d1c9ca939b63dadf8df128b86f1b9860e59c73a5e4"}, - {file = "prompt_toolkit-2.0.10.tar.gz", hash = "sha256:f15af68f66e664eaa559d4ac8a928111eebd5feda0c11738b5998045224829db"}, + {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"}, + {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"}, ] [package.dependencies] -six = ">=1.9.0" wcwidth = "*" [[package]] @@ -1357,23 +1488,23 @@ ptpython = {version = "*", markers = "python_version >= \"3.5\""} [[package]] name = "ptpython" -version = "2.0.4" +version = "3.0.29" description = "Python REPL build on top of prompt_toolkit" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "ptpython-2.0.4-py2-none-any.whl", hash = "sha256:51a74abe931f692360a32d650c2ba1ca329c08f3ed9b1de8abcd1164e0b0a6a7"}, - {file = "ptpython-2.0.4-py3-none-any.whl", hash = "sha256:938ee050e37d61c138dbbeb21383dfef8b9ed4ffb453a5f34041f42025bf5042"}, - {file = "ptpython-2.0.4.tar.gz", hash = "sha256:ebe9d68ea7532ec8ab306d4bdc7ec393701cd9bbd6eff0aa3067c821f99264d4"}, + {file = "ptpython-3.0.29-py2.py3-none-any.whl", hash = "sha256:65d75c4871859e4305a020c9b9e204366dceb4d08e0e2bd7b7511bd5e917a402"}, + {file = "ptpython-3.0.29.tar.gz", hash = "sha256:b9d625183aef93a673fc32cbe1c1fcaf51412e7a4f19590521cdaccadf25186e"}, ] [package.dependencies] -docopt = "*" -jedi = ">=0.9.0" -prompt-toolkit = ">=2.0.6,<2.1.0" +appdirs = "*" +jedi = ">=0.16.0" +prompt-toolkit = ">=3.0.43,<3.1.0" pygments = "*" [package.extras] +all = ["black"] ptipython = ["ipython"] [[package]] @@ -1415,6 +1546,17 @@ files = [ [package.extras] tests = ["pytest"] +[[package]] +name = "pycparser" +version = "2.22" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + [[package]] name = "pygments" version = "2.18.0" @@ -1491,6 +1633,17 @@ files = [ [package.dependencies] pylint = ">=1.7" +[[package]] +name = "pypng" +version = "0.20220715.0" +description = "Pure Python library for saving and loading PNG images" +optional = false +python-versions = "*" +files = [ + {file = "pypng-0.20220715.0-py3-none-any.whl", hash = "sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c"}, + {file = "pypng-0.20220715.0.tar.gz", hash = "sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1"}, +] + [[package]] name = "pytest" version = "8.2.2" @@ -1609,6 +1762,29 @@ files = [ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] +[[package]] +name = "qrcode" +version = "7.4.2" +description = "QR Code image generator" +optional = false +python-versions = ">=3.7" +files = [ + {file = "qrcode-7.4.2-py3-none-any.whl", hash = "sha256:581dca7a029bcb2deef5d01068e39093e80ef00b4a61098a2182eac59d01643a"}, + {file = "qrcode-7.4.2.tar.gz", hash = "sha256:9dd969454827e127dbd93696b20747239e6d540e082937c90f14ac95b30f5845"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} +pypng = "*" +typing-extensions = "*" + +[package.extras] +all = ["pillow (>=9.1.0)", "pytest", "pytest-cov", "tox", "zest.releaser[recommended]"] +dev = ["pytest", "pytest-cov", "tox"] +maintainer = ["zest.releaser[recommended]"] +pil = ["pillow (>=9.1.0)"] +test = ["coverage", "pytest"] + [[package]] name = "regex" version = "2023.12.25" @@ -2079,4 +2255,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.8,<4.0.0" -content-hash = "c16808ace0efb28e87518cf97bb3bcf9b85d1cd66615f3fac2345e4e385ff741" +content-hash = "36a6df024511e4351776eb6e6e9fa51296890df6f178beba00deeeaf15db5ec0" diff --git a/pyproject.toml b/pyproject.toml index 9d7f9f7..2bbed57 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ slippers = "^0.6.2" Django = "^4.0.2" Werkzeug = "^2.0.2" black = {extras = ["d"], version = "^24.4.2"} -django-allauth = ">0.63.0" +django-allauth = {extras = ["mfa"], version = "^64.0.0"} django-browser-reload = "^1.3.0" django-click = "^2.3.0" django-debug-toolbar = "^3.2.4" @@ -44,7 +44,7 @@ isort = "^5.13.2" mypy = "^1.3.0" mypy-extensions = "1.0.0" ptipython = "^1.0.1" -ptpython = "2.0.4" +ptpython = "^3.0.29" pudb = "2019.1" pylint = "^3.2.2" pylint-django = "^2.5.0" diff --git a/sample_deployment/sample_deployment/example/templates/example/base.html b/sample_deployment/sample_deployment/example/templates/example/base.html index 8b3d049..9adf410 100644 --- a/sample_deployment/sample_deployment/example/templates/example/base.html +++ b/sample_deployment/sample_deployment/example/templates/example/base.html @@ -1,3 +1,4 @@ +{# djlint:off H006 #} {% load static tailwind_tags %} diff --git a/tests/settings.py b/tests/settings.py index d67270f..e085c91 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -30,6 +30,7 @@ "allauth_ui", "allauth", "allauth.account", + "allauth.mfa", "allauth.socialaccount", "allauth.socialaccount.providers.digitalocean", "allauth.socialaccount.providers.facebook", @@ -116,3 +117,5 @@ BASE_DIR = Path(__file__).parent.parent USERSESSIONS_TRACK_ACTIVITY = True + +MFA_SUPPORTED_TYPES = ["totp", "webauthn", "recovery_codes"]