Skip to content

Commit

Permalink
Merge pull request #56 from budlight/master
Browse files Browse the repository at this point in the history
Demo Users
  • Loading branch information
aaronn committed Aug 16, 2020
2 parents 7fe00df + c6d2ccb commit 7b9239c
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 21 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,15 @@ DEFAULTS = {
# exchanging a passwordless token for a real user auth token.
'PASSWORDLESS_AUTH_TOKEN_SERIALIZER': 'drfpasswordless.serializers.TokenResponseSerializer'
# A dictionary of demo user's primary key mapped to their static pin
'PASSWORDLESS_DEMO_USERS': {},
# configurable function for sending email
'PASSWORDLESS_EMAIL_CALLBACK': 'drfpasswordless.utils.send_email_with_callback_token'
# configurable function for sending sms
'PASSWORDLESS_SMS_CALLBACK': 'drfpasswordless.utils.send_sms_with_callback_token'
}
```
Expand Down
6 changes: 3 additions & 3 deletions drfpasswordless/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class CallbackInline(AbstractCallbackTokenInline):


class AbstractCallbackTokenAdmin(UserLinkMixin, admin.ModelAdmin):
readonly_fields = ('created_at', 'user', 'key', 'type',)
list_display = ('created_at', UserLinkMixin.LINK_TO_USER_FIELD, 'key', 'type', 'is_active')
fields = ('created_at', 'user', 'key', 'type', 'is_active')
readonly_fields = ('created_at', 'user', 'key', 'type', 'to_alias_type')
list_display = ('created_at', UserLinkMixin.LINK_TO_USER_FIELD, 'key', 'type', 'is_active', 'to_alias_type')
fields = ('created_at', 'user', 'key', 'type', 'is_active', 'to_alias_type')
extra = 0
2 changes: 1 addition & 1 deletion drfpasswordless/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ def validate(self, attrs):
msg = _('Invalid alias parameters provided.')
raise serializers.ValidationError(msg)
except User.DoesNotExist:
msg = _('Invalid alias parameters provided.')
msg = _('Invalid user alias parameters provided.')
raise serializers.ValidationError(msg)
except ValidationError:
msg = _('Invalid alias parameters provided.')
Expand Down
11 changes: 7 additions & 4 deletions drfpasswordless/services.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.utils.module_loading import import_string
from drfpasswordless.settings import api_settings
from drfpasswordless.utils import (
create_callback_token_for_user,
send_email_with_callback_token,
send_sms_with_callback_token
)


Expand All @@ -10,10 +10,13 @@ class TokenService(object):
def send_token(user, alias_type, token_type, **message_payload):
token = create_callback_token_for_user(user, alias_type, token_type)
send_action = None

if user.pk in api_settings.PASSWORDLESS_DEMO_USERS.keys():
return True
if alias_type == 'email':
send_action = send_email_with_callback_token
send_action = import_string(api_settings.PASSWORDLESS_EMAIL_CALLBACK)
elif alias_type == 'mobile':
send_action = send_sms_with_callback_token
send_action = import_string(api_settings.PASSWORDLESS_SMS_CALLBACK)
# Send to alias
success = send_action(user, token, **message_payload)
return success
8 changes: 7 additions & 1 deletion drfpasswordless/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,13 @@

# What function is called to construct a serializer for drf tokens when
# exchanging a passwordless token for a real user auth token.
'PASSWORDLESS_AUTH_TOKEN_SERIALIZER': 'drfpasswordless.serializers.TokenResponseSerializer'
'PASSWORDLESS_AUTH_TOKEN_SERIALIZER': 'drfpasswordless.serializers.TokenResponseSerializer',

# A dictionary of demo user's primary key mapped to their static pin
'PASSWORDLESS_DEMO_USERS': {},
'PASSWORDLESS_EMAIL_CALLBACK': 'drfpasswordless.utils.send_email_with_callback_token',
'PASSWORDLESS_SMS_CALLBACK': 'drfpasswordless.utils.send_sms_with_callback_token',

}

# List of settings that may be in string import notation.
Expand Down
4 changes: 4 additions & 0 deletions drfpasswordless/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ def invalidate_previous_tokens(sender, instance, created, **kwargs):
"""
Invalidates all previously issued tokens of that type when a new one is created, used, or anything like that.
"""

if instance.user.pk in api_settings.PASSWORDLESS_DEMO_USERS.keys():
return

if isinstance(instance, CallbackToken):
CallbackToken.objects.active().filter(user=instance.user, type=instance.type).exclude(id=instance.id).update(is_active=False)

Expand Down
33 changes: 21 additions & 12 deletions drfpasswordless/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,28 @@ def authenticate_by_token(callback_token):


def create_callback_token_for_user(user, alias_type, token_type):

token = None
alias_type_u = alias_type.upper()
to_alias_field = getattr(api_settings, f'PASSWORDLESS_USER_{alias_type_u}_FIELD_NAME')
if user.pk in api_settings.PASSWORDLESS_DEMO_USERS.keys():
token = CallbackToken.objects.filter(user=user).first()
if token:
return token
else:
return CallbackToken.objects.create(
user=user,
key=api_settings.PASSWORDLESS_DEMO_USERS[user.pk],
to_alias_type=alias_type_u,
to_alias=getattr(user, to_alias_field),
type=token_type
)

token = CallbackToken.objects.create(user=user,
to_alias_type=alias_type_u,
to_alias=getattr(user, to_alias_field),
type=token_type)

if alias_type_u == 'EMAIL':
token = CallbackToken.objects.create(user=user,
to_alias_type=alias_type_u,
to_alias=getattr(user, api_settings.PASSWORDLESS_USER_EMAIL_FIELD_NAME),
type=token_type)

elif alias_type_u == 'MOBILE':
token = CallbackToken.objects.create(user=user,
to_alias_type=alias_type_u,
to_alias=getattr(user, api_settings.PASSWORDLESS_USER_MOBILE_FIELD_NAME),
type=token_type)

if token is not None:
return token
Expand All @@ -62,11 +69,13 @@ def validate_token_age(callback_token):
"""
Returns True if a given token is within the age expiration limit.
"""

try:
token = CallbackToken.objects.get(key=callback_token, is_active=True)
seconds = (timezone.now() - token.created_at).total_seconds()
token_expiry_time = api_settings.PASSWORDLESS_TOKEN_EXPIRE_TIME

if token.user.pk in api_settings.PASSWORDLESS_DEMO_USERS.keys():
return True
if seconds <= token_expiry_time:
return True
else:
Expand Down

0 comments on commit 7b9239c

Please sign in to comment.