Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,9 @@ DEFAULTS = {
# configurable function for sending sms
'PASSWORDLESS_SMS_CALLBACK': 'drfpasswordless.utils.send_sms_with_callback_token'

# Token Generation Retry Count
'PASSWORDLESS_TOKEN_GENERATION_ATTEMPTS': 3


}
```
Expand Down
2 changes: 1 addition & 1 deletion drfpasswordless/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-

__title__ = 'drfpasswordless'
__version__ = '1.5.6'
__version__ = '1.5.7'
__author__ = 'Aaron Ng'
__license__ = 'MIT'
__copyright__ = 'Copyright 2020 Aaron Ng'
Expand Down
2 changes: 1 addition & 1 deletion drfpasswordless/__version__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
VERSION = (1, 5, 6)
VERSION = (1, 5, 7)

__version__ = '.'.join(map(str, VERSION))
17 changes: 17 additions & 0 deletions drfpasswordless/migrations/0005_auto_20201117_0410.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 3.0.2 on 2020-11-17 04:10

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('drfpasswordless', '0004_auto_20200125_0853'),
]

operations = [
migrations.AlterUniqueTogether(
name='callbacktoken',
unique_together=set(),
),
]
2 changes: 0 additions & 2 deletions drfpasswordless/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ class Meta:
abstract = True
get_latest_by = 'created_at'
ordering = ['-id']
unique_together = (('key', 'is_active'),)

def __str__(self):
return str(self.key)
Expand All @@ -66,4 +65,3 @@ class CallbackToken(AbstractBaseCallbackToken):

class Meta(AbstractBaseCallbackToken.Meta):
verbose_name = 'Callback Token'
unique_together = ['is_active', 'key', 'type']
2 changes: 2 additions & 0 deletions drfpasswordless/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@
'PASSWORDLESS_EMAIL_CALLBACK': 'drfpasswordless.utils.send_email_with_callback_token',
'PASSWORDLESS_SMS_CALLBACK': 'drfpasswordless.utils.send_sms_with_callback_token',

# Token Generation Retry Count
'PASSWORDLESS_TOKEN_GENERATION_ATTEMPTS': 3
}

# List of settings that may be in string import notation.
Expand Down
28 changes: 26 additions & 2 deletions drfpasswordless/signals.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.dispatch import receiver
from django.db.models import signals
from drfpasswordless.models import CallbackToken
Expand Down Expand Up @@ -27,18 +28,41 @@ def invalidate_previous_tokens(sender, instance, created, **kwargs):
def check_unique_tokens(sender, instance, **kwargs):
"""
Ensures that mobile and email tokens are unique or tries once more to generate.
Note that here we've decided keys are unique even across auth and validation.
We could consider relaxing this in the future as well by filtering on the instance.type.
"""
if instance._state.adding:
# save is called on a token to create it in the db
# before creating check whether a token with the same key exists
if isinstance(instance, CallbackToken):
unique = False
tries = 0

if CallbackToken.objects.filter(key=instance.key, is_active=True).exists():
instance.key = generate_numeric_token()
# Try N(default=3) times before giving up.
while tries < api_settings.PASSWORDLESS_TOKEN_GENERATION_ATTEMPTS:
tries = tries + 1
new_key = generate_numeric_token()
instance.key = new_key

if not CallbackToken.objects.filter(key=instance.key, is_active=True).exists():
# Leave the loop if we found a valid token that doesn't exist yet.
unique = True
break

if not unique:
# A unique value wasn't found after three tries
raise ValidationError("Couldn't create a unique token even after retrying.")
else:
# A unique value was found immediately.
pass


else:
# save is called on an already existing token to update it. Such as invalidating it.
# in that case there is no need to check for the key. This way we both avoid an unneccessary db hit
# and avoid to change key field of used tokens.
pass
pass



Expand Down