4
4
from django .core .exceptions import PermissionDenied
5
5
from django .core .validators import RegexValidator
6
6
from rest_framework import serializers
7
+ from rest_framework .exceptions import ValidationError
7
8
from drfpasswordless .models import CallbackToken
8
9
from drfpasswordless .settings import api_settings
9
10
from drfpasswordless .utils import authenticate_by_token , verify_user_alias , validate_token_age
@@ -168,21 +169,48 @@ class AbstractBaseCallbackTokenSerializer(serializers.Serializer):
168
169
Abstract class inspired by DRF's own token serializer.
169
170
Returns a user if valid, None or a message if not.
170
171
"""
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 )
171
178
token = TokenField (min_length = 6 , max_length = 6 , validators = [token_age_validator ])
172
179
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
+
173
197
174
198
class CallbackTokenAuthSerializer (AbstractBaseCallbackTokenSerializer ):
175
199
176
200
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 })
180
210
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.
186
214
if not user .is_active :
187
215
msg = _ ('User account is disabled.' )
188
216
raise serializers .ValidationError (msg )
@@ -203,8 +231,11 @@ def validate(self, attrs):
203
231
else :
204
232
msg = _ ('Invalid Token' )
205
233
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.' )
208
239
raise serializers .ValidationError (msg )
209
240
210
241
@@ -216,15 +247,17 @@ class CallbackTokenVerificationSerializer(AbstractBaseCallbackTokenSerializer):
216
247
217
248
def validate (self , attrs ):
218
249
try :
250
+ alias_type , alias = self .validate_alias (attrs )
219
251
user_id = self .context .get ("user_id" )
252
+ user = User .objects .get (** {'id' : user_id , alias_type : alias })
220
253
callback_token = attrs .get ('token' , None )
221
254
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 })
224
259
225
260
if token .user == user :
226
- # Check that the token.user is the request.user
227
-
228
261
# Mark this alias as verified
229
262
success = verify_user_alias (user , token )
230
263
if success is False :
@@ -237,11 +270,11 @@ def validate(self, attrs):
237
270
logger .debug ("drfpasswordless: User token mismatch when verifying alias." )
238
271
239
272
except CallbackToken .DoesNotExist :
240
- msg = _ ('Missing authentication token .' )
273
+ msg = _ ('We could not verify this alias .' )
241
274
logger .debug ("drfpasswordless: Tried to validate alias with bad token." )
242
275
pass
243
276
except User .DoesNotExist :
244
- msg = _ ('Missing user .' )
277
+ msg = _ ('We could not verify this alias .' )
245
278
logger .debug ("drfpasswordless: Tried to validate alias with bad user." )
246
279
pass
247
280
except PermissionDenied :
0 commit comments