44from django .core .exceptions import PermissionDenied
55from django .core .validators import RegexValidator
66from rest_framework import serializers
7+ from rest_framework .exceptions import ValidationError
78from drfpasswordless .models import CallbackToken
89from drfpasswordless .settings import api_settings
910from drfpasswordless .utils import authenticate_by_token , verify_user_alias , validate_token_age
@@ -168,21 +169,48 @@ class AbstractBaseCallbackTokenSerializer(serializers.Serializer):
168169 Abstract class inspired by DRF's own token serializer.
169170 Returns a user if valid, None or a message if not.
170171 """
172+ phone_regex = RegexValidator (regex = r'^\+?1?\d{9,15}$' ,
173+ message = "Mobile number must be entered in the format:"
174+ " '+999999999'. Up to 15 digits allowed." )
175+
176+ email = serializers .EmailField (required = False ) # Needs to be required=false to require both.
177+ mobile = serializers .CharField (required = False , validators = [phone_regex ], max_length = 15 )
171178 token = TokenField (min_length = 6 , max_length = 6 , validators = [token_age_validator ])
172179
180+ def validate_alias (self , attrs ):
181+ email = attrs .get ('email' , None )
182+ mobile = attrs .get ('mobile' , None )
183+
184+ if email and mobile :
185+ raise serializers .ValidationError ()
186+
187+ if not email and not mobile :
188+ raise serializers .ValidationError ()
189+
190+ if email :
191+ return 'email' , email
192+ elif mobile :
193+ return 'mobile' , mobile
194+
195+ return None
196+
173197
174198class CallbackTokenAuthSerializer (AbstractBaseCallbackTokenSerializer ):
175199
176200 def validate (self , attrs ):
177- callback_token = attrs .get ('token' , None )
178-
179- token = CallbackToken .objects .get (key = callback_token , is_active = True )
201+ # Check Aliases
202+ try :
203+ alias_type , alias = self .validate_alias (attrs )
204+ callback_token = attrs .get ('token' , None )
205+ user = User .objects .get (** {alias_type : alias })
206+ token = CallbackToken .objects .get (** {'user' : user ,
207+ 'key' : callback_token ,
208+ 'type' : CallbackToken .TOKEN_TYPE_AUTH ,
209+ 'is_active' : True })
180210
181- if token :
182- # Check the token type for our uni-auth method.
183- # authenticates and checks the expiry of the callback token.
184- user = authenticate_by_token (token )
185- if user :
211+ if token .user == user :
212+ # Check the token type for our uni-auth method.
213+ # authenticates and checks the expiry of the callback token.
186214 if not user .is_active :
187215 msg = _ ('User account is disabled.' )
188216 raise serializers .ValidationError (msg )
@@ -203,8 +231,11 @@ def validate(self, attrs):
203231 else :
204232 msg = _ ('Invalid Token' )
205233 raise serializers .ValidationError (msg )
206- else :
207- msg = _ ('Missing authentication token.' )
234+ except User .DoesNotExist :
235+ msg = _ ('Invalid alias parameters provided.' )
236+ raise serializers .ValidationError (msg )
237+ except ValidationError :
238+ msg = _ ('Invalid alias parameters provided.' )
208239 raise serializers .ValidationError (msg )
209240
210241
@@ -216,15 +247,17 @@ class CallbackTokenVerificationSerializer(AbstractBaseCallbackTokenSerializer):
216247
217248 def validate (self , attrs ):
218249 try :
250+ alias_type , alias = self .validate_alias (attrs )
219251 user_id = self .context .get ("user_id" )
252+ user = User .objects .get (** {'id' : user_id , alias_type : alias })
220253 callback_token = attrs .get ('token' , None )
221254
222- token = CallbackToken .objects .get (key = callback_token , is_active = True )
223- user = User .objects .get (pk = user_id )
255+ token = CallbackToken .objects .get (** {'user' : user ,
256+ 'key' : callback_token ,
257+ 'type' : CallbackToken .TOKEN_TYPE_VERIFY ,
258+ 'is_active' : True })
224259
225260 if token .user == user :
226- # Check that the token.user is the request.user
227-
228261 # Mark this alias as verified
229262 success = verify_user_alias (user , token )
230263 if success is False :
@@ -237,11 +270,11 @@ def validate(self, attrs):
237270 logger .debug ("drfpasswordless: User token mismatch when verifying alias." )
238271
239272 except CallbackToken .DoesNotExist :
240- msg = _ ('Missing authentication token .' )
273+ msg = _ ('We could not verify this alias .' )
241274 logger .debug ("drfpasswordless: Tried to validate alias with bad token." )
242275 pass
243276 except User .DoesNotExist :
244- msg = _ ('Missing user .' )
277+ msg = _ ('We could not verify this alias .' )
245278 logger .debug ("drfpasswordless: Tried to validate alias with bad user." )
246279 pass
247280 except PermissionDenied :
0 commit comments