diff --git a/InvenTree/users/migrations/0011_auto_20240119_1659.py b/InvenTree/users/migrations/0011_auto_20240119_1659.py new file mode 100644 index 000000000000..241ddd9ff4d9 --- /dev/null +++ b/InvenTree/users/migrations/0011_auto_20240119_1659.py @@ -0,0 +1,45 @@ +# Generated by Django 3.2.23 on 2024-01-19 16:59 + +import base64 + +from django.db import migrations + +from allauth.mfa.adapter import get_adapter +from allauth.mfa.models import Authenticator +from django_otp.plugins.otp_static.models import StaticDevice +from django_otp.plugins.otp_totp.models import TOTPDevice + + +def move_mfa(apps, schema_editor): + """Data migration to switch to django-allauth's new built-in MFA.""" + adapter = get_adapter() + authenticators = [] + for totp in TOTPDevice.objects.filter(confirmed=True).iterator(): + recovery_codes = set() + for sdevice in StaticDevice.objects.filter( + confirmed=True, user_id=totp.user_id + ).iterator(): + recovery_codes.update(sdevice.token_set.values_list('token', flat=True)) + secret = base64.b32encode(bytes.fromhex(totp.key)).decode('ascii') + totp_authenticator = Authenticator( + user_id=totp.user_id, + type=Authenticator.Type.TOTP, + data={'secret': adapter.encrypt(secret)}, + ) + authenticators.append(totp_authenticator) + authenticators.append( + Authenticator( + user_id=totp.user_id, + type=Authenticator.Type.RECOVERY_CODES, + data={'migrated_codes': [adapter.encrypt(c) for c in recovery_codes]}, + ) + ) + Authenticator.objects.bulk_create(authenticators) + + +class Migration(migrations.Migration): + dependencies = [('users', '0010_alter_apitoken_key')] + + operations = [ + migrations.RunPython(move_mfa, reverse_code=migrations.RunPython.noop) + ] diff --git a/requirements.in b/requirements.in index ce2a2a36bb79..c9d54024520b 100644 --- a/requirements.in +++ b/requirements.in @@ -3,7 +3,6 @@ Django>=3.2.14,<4 # Django package coreapi # API documentation for djangorestframework cryptography>=40.0.0,!=40.0.2 # Core cryptographic functionality django-allauth # SSO for external providers via OpenID -django-allauth-2fa # MFA / 2FA django-cleanup # Automated deletion of old / unused uploaded files django-cors-headers # CORS headers extension for DRF django-crispy-forms<2.0 # Form helpers # FIXED 2023-02-18 due to required updates in the new version diff --git a/requirements.txt b/requirements.txt index 22652b35c44d..a2722dbb6abb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -64,7 +64,6 @@ django==3.2.23 # -r requirements.in # dj-rest-auth # django-allauth - # django-allauth-2fa # django-cors-headers # django-dbbackup # django-error-report-2 @@ -96,9 +95,6 @@ django==3.2.23 django-allauth==0.59.0 # via # -r requirements.in - # django-allauth-2fa -django-allauth-2fa==0.11.1 - # via -r requirements.in django-cleanup==8.0.0 # via -r requirements.in django-cors-headers==4.3.0 @@ -129,8 +125,6 @@ django-money==3.2.0 # via -r requirements.in django-mptt==0.11.0 # via -r requirements.in -django-otp==1.2.4 - # via django-allauth-2fa django-picklefield==3.1 # via django-q2 django-q-sentry==0.1.6 @@ -334,7 +328,6 @@ pyyaml==6.0.1 qrcode[pil]==7.4.2 # via # -r requirements.in - # django-allauth-2fa rapidfuzz==0.7.6 # via -r requirements.in redis==5.0.1