Skip to content

Commit d0ca1c9

Browse files
committed
fix: new otp secret
1 parent 13cae05 commit d0ca1c9

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

Diff for: codeforlife/user/signals/auth_factor.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""
2+
© Ocado Group
3+
Created on 17/01/2025 at 15:55:22(+00:00).
4+
"""
5+
6+
import pyotp
7+
from django.db.models import signals
8+
from django.dispatch import receiver
9+
10+
from ..models import AuthFactor
11+
12+
# pylint: disable=missing-function-docstring
13+
# pylint: disable=unused-argument
14+
15+
16+
@receiver(signals.post_delete, sender=AuthFactor)
17+
def auth_factor__post_delete(sender, instance: AuthFactor, **kwargs):
18+
# Create new secret to ensure secrets are not recycled.
19+
if instance.type == AuthFactor.Type.OTP:
20+
otp_secret = instance.user.userprofile.otp_secret
21+
# Ensure the randomly generated new secret is different to the previous.
22+
while otp_secret == instance.user.userprofile.otp_secret:
23+
instance.user.userprofile.otp_secret = pyotp.random_base32()
24+
25+
instance.user.userprofile.save(update_fields=["otp_secret"])

Diff for: codeforlife/user/signals/auth_factor_test.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""
2+
© Ocado Group
3+
Created on 17/01/2025 at 16:04:46(+00:00).
4+
"""
5+
6+
from django.test import TestCase
7+
8+
from ..models import AuthFactor
9+
10+
11+
# pylint: disable-next=missing-class-docstring
12+
class TestAuthFactor(TestCase):
13+
fixtures = ["school_2"]
14+
15+
def test_post_delete(self):
16+
"""Deleting an otp-auth-factor assigns a new otp-secret to its user."""
17+
auth_factor = AuthFactor.objects.filter(
18+
type=AuthFactor.Type.OTP
19+
).first()
20+
assert auth_factor
21+
22+
userprofile = auth_factor.user.userprofile
23+
otp_secret = userprofile.otp_secret
24+
25+
auth_factor.delete()
26+
27+
userprofile.refresh_from_db()
28+
assert otp_secret != userprofile.otp_secret

0 commit comments

Comments
 (0)