From 3ab99301213ec60d669f888a9385a7bf91770c39 Mon Sep 17 00:00:00 2001 From: Ben Holloway Date: Mon, 6 Apr 2020 14:16:47 -0700 Subject: [PATCH 01/15] change one error message From e0d427fba1722fc99b84a7525827bac31b5d0796 Mon Sep 17 00:00:00 2001 From: Suroor Hussain Date: Thu, 2 Apr 2020 02:49:42 +0530 Subject: [PATCH 02/15] Separate out sending sms via twilio to a function. This is done so that the function to send sms can be made pluggable (user customisable) in the future --- drfpasswordless/utils.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drfpasswordless/utils.py b/drfpasswordless/utils.py index ba02deb..a6bd78a 100644 --- a/drfpasswordless/utils.py +++ b/drfpasswordless/utils.py @@ -173,7 +173,15 @@ def send_sms_with_callback_token(user, mobile_token, **kwargs): return True base_string = kwargs.get('mobile_message', api_settings.PASSWORDLESS_MOBILE_MESSAGE) + message = base_string % mobile_token.key + to_number = getattr(user, api_settings.PASSWORDLESS_USER_MOBILE_FIELD_NAME) + if to_number.__class__.__name__ == 'PhoneNumber': + to_number = to_number.__str__() + + return send_twilio_sms(to_number, message) + +def send_twilio_sms(to_number, message): try: if api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER: # We need a sending number to send properly @@ -181,12 +189,8 @@ def send_sms_with_callback_token(user, mobile_token, **kwargs): from twilio.rest import Client twilio_client = Client(os.environ['TWILIO_ACCOUNT_SID'], os.environ['TWILIO_AUTH_TOKEN']) - to_number = getattr(user, api_settings.PASSWORDLESS_USER_MOBILE_FIELD_NAME) - if to_number.__class__.__name__ == 'PhoneNumber': - to_number = to_number.__str__() - twilio_client.messages.create( - body=base_string % mobile_token.key, + body=message, to=to_number, from_=api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER ) @@ -201,9 +205,9 @@ def send_sms_with_callback_token(user, mobile_token, **kwargs): logger.debug("Couldn't send SMS." "Did you set your Twilio account tokens and specify a PASSWORDLESS_MOBILE_NOREPLY_NUMBER?") except Exception as e: - logger.debug("Failed to send token SMS to user: {}. " + logger.debug("Failed to send token SMS to user. " "Possibly no mobile number on user object or the twilio package isn't set up yet. " - "Number entered was {}".format(user.id, getattr(user, api_settings.PASSWORDLESS_USER_MOBILE_FIELD_NAME))) + "Number entered was {}".format(getattr(to_number))) logger.debug(e) return False From e3d928c54ff17c2a36fde6aeee059946c41adacf Mon Sep 17 00:00:00 2001 From: Suroor Hussain Date: Thu, 2 Apr 2020 03:47:28 +0530 Subject: [PATCH 03/15] Adds support for sending sms with getlead --- drfpasswordless/utils.py | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drfpasswordless/utils.py b/drfpasswordless/utils.py index a6bd78a..48aa7a0 100644 --- a/drfpasswordless/utils.py +++ b/drfpasswordless/utils.py @@ -179,7 +179,10 @@ def send_sms_with_callback_token(user, mobile_token, **kwargs): if to_number.__class__.__name__ == 'PhoneNumber': to_number = to_number.__str__() - return send_twilio_sms(to_number, message) + if os.environ.get('TWILIO_ACCOUNT_SID'): + return send_twilio_sms(to_number, message) + else: + return send_getlead_sms(to_number, mobile_token.key) def send_twilio_sms(to_number, message): try: @@ -211,6 +214,41 @@ def send_twilio_sms(to_number, message): logger.debug(e) return False +def send_getlead_sms(to_number, code): + try: + if api_settings.PASSWORDLESS_TEST_SUPPRESSION is True: + # we assume success to prevent spamming SMS during testing. + return True + + import requests + api_url = 'https://app.getlead.co.uk/api/push-otp' + data = dict( + username=os.environ['GETLEAD_UID'], + token=os.environ['GETLEAD_TOKEN'], + sender=os.environ['GETLEAD_SENDER'], + to=to_number, + otp=code, + purpose='login', + company='CitzConn', + priority=4 + ) + + response = requests.post(api_url, data=data).json() + if response.get("status") == "Fail": + return False + return True + except ImportError: + logger.debug("Couldn't import requests library. Is requests installed?") + return False + except KeyError: + logger.debug("Couldn't send SMS." + "Did you set your GetLead account tokens?") + except Exception as e: + logger.debug("Failed to send token SMS to user. " + "Possibly no mobile number on user object or the twilio package isn't set up yet. " + "Number entered was {}".format(to_number)) + logger.exception(e) + return False def create_authentication_token(user): """ Default way to create an authentication token""" From e265ebbcdd78c9a87637ff95a04d00c1116c32f0 Mon Sep 17 00:00:00 2001 From: Athul KP Date: Sat, 9 May 2020 17:59:38 +0530 Subject: [PATCH 04/15] Fixes Bug. --- drfpasswordless/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drfpasswordless/utils.py b/drfpasswordless/utils.py index 48aa7a0..4fe2dcd 100644 --- a/drfpasswordless/utils.py +++ b/drfpasswordless/utils.py @@ -210,7 +210,7 @@ def send_twilio_sms(to_number, message): except Exception as e: logger.debug("Failed to send token SMS to user. " "Possibly no mobile number on user object or the twilio package isn't set up yet. " - "Number entered was {}".format(getattr(to_number))) + "Number entered was {}".format(to_number)) logger.debug(e) return False From 63ee3ee67d3fc9623a098b759aec635e4abf39bc Mon Sep 17 00:00:00 2001 From: Tim Stallmann Date: Thu, 16 Apr 2020 11:39:15 -0400 Subject: [PATCH 05/15] Immediately return true if PASSWORDLESS_TEST_SUPPRESSION set --- drfpasswordless/utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/drfpasswordless/utils.py b/drfpasswordless/utils.py index 4fe2dcd..c0f5cad 100644 --- a/drfpasswordless/utils.py +++ b/drfpasswordless/utils.py @@ -165,11 +165,9 @@ def send_sms_with_callback_token(user, mobile_token, **kwargs): """ if api_settings.PASSWORDLESS_TEST_SUPPRESSION is True: # we assume success to prevent spamming SMS during testing. - # even if you have suppression on– you must provide a number if you have mobile selected. if api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER is None: return False - return True base_string = kwargs.get('mobile_message', api_settings.PASSWORDLESS_MOBILE_MESSAGE) From 96d6edde01c8219e80c71db3e1341ec9266b4ae1 Mon Sep 17 00:00:00 2001 From: Suroor Hussain Date: Thu, 2 Apr 2020 02:49:42 +0530 Subject: [PATCH 06/15] Separate out sending sms via twilio to a function. This is done so that the function to send sms can be made pluggable (user customisable) in the future --- drfpasswordless/utils.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drfpasswordless/utils.py b/drfpasswordless/utils.py index c0f5cad..60a8383 100644 --- a/drfpasswordless/utils.py +++ b/drfpasswordless/utils.py @@ -177,10 +177,7 @@ def send_sms_with_callback_token(user, mobile_token, **kwargs): if to_number.__class__.__name__ == 'PhoneNumber': to_number = to_number.__str__() - if os.environ.get('TWILIO_ACCOUNT_SID'): - return send_twilio_sms(to_number, message) - else: - return send_getlead_sms(to_number, mobile_token.key) + return send_twilio_sms(to_number, message) def send_twilio_sms(to_number, message): try: @@ -208,7 +205,7 @@ def send_twilio_sms(to_number, message): except Exception as e: logger.debug("Failed to send token SMS to user. " "Possibly no mobile number on user object or the twilio package isn't set up yet. " - "Number entered was {}".format(to_number)) + "Number entered was {}".format(getattr(to_number))) logger.debug(e) return False From 9bffc229f4192f05abd6b568964be7c4b072c86a Mon Sep 17 00:00:00 2001 From: Athul KP Date: Tue, 25 Aug 2020 15:19:53 +0530 Subject: [PATCH 07/15] Cleanup: corrects indentations. --- drfpasswordless/utils.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drfpasswordless/utils.py b/drfpasswordless/utils.py index 60a8383..7f16914 100644 --- a/drfpasswordless/utils.py +++ b/drfpasswordless/utils.py @@ -201,14 +201,15 @@ def send_twilio_sms(to_number, message): return False except KeyError: logger.debug("Couldn't send SMS." - "Did you set your Twilio account tokens and specify a PASSWORDLESS_MOBILE_NOREPLY_NUMBER?") + "Did you set your Twilio account tokens and specify a PASSWORDLESS_MOBILE_NOREPLY_NUMBER?") except Exception as e: logger.debug("Failed to send token SMS to user. " - "Possibly no mobile number on user object or the twilio package isn't set up yet. " - "Number entered was {}".format(getattr(to_number))) + "Possibly no mobile number on user object or the twilio package isn't set up yet. " + "Number entered was {}".format(to_number)) logger.debug(e) return False + def send_getlead_sms(to_number, code): try: if api_settings.PASSWORDLESS_TEST_SUPPRESSION is True: @@ -219,13 +220,13 @@ def send_getlead_sms(to_number, code): api_url = 'https://app.getlead.co.uk/api/push-otp' data = dict( username=os.environ['GETLEAD_UID'], - token=os.environ['GETLEAD_TOKEN'], - sender=os.environ['GETLEAD_SENDER'], - to=to_number, - otp=code, - purpose='login', - company='CitzConn', - priority=4 + token=os.environ['GETLEAD_TOKEN'], + sender=os.environ['GETLEAD_SENDER'], + to=to_number, + otp=code, + purpose='login', + company='CitzConn', + priority=4 ) response = requests.post(api_url, data=data).json() @@ -237,14 +238,15 @@ def send_getlead_sms(to_number, code): return False except KeyError: logger.debug("Couldn't send SMS." - "Did you set your GetLead account tokens?") + "Did you set your GetLead account tokens?") except Exception as e: logger.debug("Failed to send token SMS to user. " - "Possibly no mobile number on user object or the twilio package isn't set up yet. " - "Number entered was {}".format(to_number)) + "Possibly no mobile number on user object or the twilio package isn't set up yet. " + "Number entered was {}".format(to_number)) logger.exception(e) return False + def create_authentication_token(user): """ Default way to create an authentication token""" return Token.objects.get_or_create(user=user) From 8ce91ce51eda2249c1f000b83626a1e82e96b90b Mon Sep 17 00:00:00 2001 From: Athul KP Date: Tue, 25 Aug 2020 15:52:07 +0530 Subject: [PATCH 08/15] Adds send_plivo_sms. --- drfpasswordless/utils.py | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drfpasswordless/utils.py b/drfpasswordless/utils.py index 7f16914..aca709c 100644 --- a/drfpasswordless/utils.py +++ b/drfpasswordless/utils.py @@ -177,7 +177,13 @@ def send_sms_with_callback_token(user, mobile_token, **kwargs): if to_number.__class__.__name__ == 'PhoneNumber': to_number = to_number.__str__() - return send_twilio_sms(to_number, message) + if os.environ.get('TWILIO_ACCOUNT_SID'): + return send_twilio_sms(to_number, message) + elif os.environ.get('GETLEAD_UID'): + return send_getlead_sms(to_number, mobile_token.key) + else: + return send_plivo_sms(to_number, message) + def send_twilio_sms(to_number, message): try: @@ -247,6 +253,38 @@ def send_getlead_sms(to_number, code): return False +def send_plivo_sms(to_number, message): + try: + if api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER: + # We need a sending number to send properly + if api_settings.PASSWORDLESS_TEST_SUPPRESSION is True: + # we assume success to prevent spamming SMS during testing. + return True + from plivo import RestClient + client = RestClient(os.environ["PLIVO_AUTH_ID"], os.environ["PLIVO_AUTH_TOKEN"]) + client.messages.create( + src=api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER, + dst=to_number, + text=message, + ) + return True + else: + logger.debug("Failed to send token sms. Missing PASSWORDLESS_MOBILE_NOREPLY_NUMBER.") + return False + except ImportError: + logger.debug("Couldn't import plivo library. Is plivo installed?") + return False + except KeyError: + logger.debug("Couldn't send SMS." + "Did you set your Plivo account tokens?") + except Exception as e: + logger.debug("Failed to send token SMS to user. " + "Possibly no mobile number on user object or the plivo package isn't set up yet. " + "Number entered was {}".format(to_number)) + logger.exception(e) + return False + + def create_authentication_token(user): """ Default way to create an authentication token""" return Token.objects.get_or_create(user=user) From 3eef7a56a03be64dc133c180b96700e7b43185e1 Mon Sep 17 00:00:00 2001 From: Athul KP Date: Tue, 25 Aug 2020 17:17:40 +0530 Subject: [PATCH 09/15] Refactors utils for sms provider. --- drfpasswordless/utils.py | 144 +++++++++++++++------------------------ 1 file changed, 54 insertions(+), 90 deletions(-) diff --git a/drfpasswordless/utils.py b/drfpasswordless/utils.py index aca709c..58f94b9 100644 --- a/drfpasswordless/utils.py +++ b/drfpasswordless/utils.py @@ -169,7 +169,6 @@ def send_sms_with_callback_token(user, mobile_token, **kwargs): if api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER is None: return False return True - base_string = kwargs.get('mobile_message', api_settings.PASSWORDLESS_MOBILE_MESSAGE) message = base_string % mobile_token.key @@ -177,112 +176,77 @@ def send_sms_with_callback_token(user, mobile_token, **kwargs): if to_number.__class__.__name__ == 'PhoneNumber': to_number = to_number.__str__() - if os.environ.get('TWILIO_ACCOUNT_SID'): - return send_twilio_sms(to_number, message) - elif os.environ.get('GETLEAD_UID'): - return send_getlead_sms(to_number, mobile_token.key) - else: - return send_plivo_sms(to_number, message) - - -def send_twilio_sms(to_number, message): + if not api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER: + logger.debug("Failed to send token sms. Missing PASSWORDLESS_MOBILE_NOREPLY_NUMBER.") + return False try: - if api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER: - # We need a sending number to send properly - - from twilio.rest import Client - twilio_client = Client(os.environ['TWILIO_ACCOUNT_SID'], os.environ['TWILIO_AUTH_TOKEN']) - - twilio_client.messages.create( - body=message, - to=to_number, - from_=api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER - ) - return True - else: - logger.debug("Failed to send token sms. Missing PASSWORDLESS_MOBILE_NOREPLY_NUMBER.") + provider = os.environ.get('PASSWORDLESS_SMS_PROVIDER', 'TWILIO') + SMS_PROVIDERS = { + 'TWILIO': send_twilio_sms, + 'GETLEAD': send_getlead_sms, + 'PLIVO': send_plivo_sms, + } + try: + handler = SMS_PROVIDERS[provider] + except KeyError: + logger.debug("SMS-Provider not found.") return False + else: + return handler(to_number, message, mobile_token.key) except ImportError: - logger.debug("Couldn't import Twilio client. Is twilio installed?") + logger.debug("Couldn't import SMS-Provider client. Is SMS-Provider installed?") return False except KeyError: logger.debug("Couldn't send SMS." - "Did you set your Twilio account tokens and specify a PASSWORDLESS_MOBILE_NOREPLY_NUMBER?") + "Did you set your SMS-Provider account tokens and specify a PASSWORDLESS_MOBILE_NOREPLY_NUMBER?") except Exception as e: logger.debug("Failed to send token SMS to user. " - "Possibly no mobile number on user object or the twilio package isn't set up yet. " + "Possibly no mobile number on user object or the SMS-Provider package isn't set up yet. " "Number entered was {}".format(to_number)) logger.debug(e) return False -def send_getlead_sms(to_number, code): - try: - if api_settings.PASSWORDLESS_TEST_SUPPRESSION is True: - # we assume success to prevent spamming SMS during testing. - return True +def send_twilio_sms(to_number, message, code): + from twilio.rest import Client + twilio_client = Client(os.environ['TWILIO_ACCOUNT_SID'], os.environ['TWILIO_AUTH_TOKEN']) + twilio_client.messages.create( + body=message, + to=to_number, + from_=api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER + ) + return True - import requests - api_url = 'https://app.getlead.co.uk/api/push-otp' - data = dict( - username=os.environ['GETLEAD_UID'], - token=os.environ['GETLEAD_TOKEN'], - sender=os.environ['GETLEAD_SENDER'], - to=to_number, - otp=code, - purpose='login', - company='CitzConn', - priority=4 - ) - - response = requests.post(api_url, data=data).json() - if response.get("status") == "Fail": - return False - return True - except ImportError: - logger.debug("Couldn't import requests library. Is requests installed?") - return False - except KeyError: - logger.debug("Couldn't send SMS." - "Did you set your GetLead account tokens?") - except Exception as e: - logger.debug("Failed to send token SMS to user. " - "Possibly no mobile number on user object or the twilio package isn't set up yet. " - "Number entered was {}".format(to_number)) - logger.exception(e) + +def send_getlead_sms(to_number, message, code): + import requests + api_url = 'https://app.getlead.co.uk/api/push-otp' + data = dict( + username=os.environ['GETLEAD_UID'], + token=os.environ['GETLEAD_TOKEN'], + sender=api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER, + to=to_number, + otp=code, + purpose='login', + company=os.environ['GETLEAD_COMPANY_NAME'], + priority=4 + ) + + response = requests.post(api_url, data=data).json() + if response.get("status") == "Fail": return False + return True -def send_plivo_sms(to_number, message): - try: - if api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER: - # We need a sending number to send properly - if api_settings.PASSWORDLESS_TEST_SUPPRESSION is True: - # we assume success to prevent spamming SMS during testing. - return True - from plivo import RestClient - client = RestClient(os.environ["PLIVO_AUTH_ID"], os.environ["PLIVO_AUTH_TOKEN"]) - client.messages.create( - src=api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER, - dst=to_number, - text=message, - ) - return True - else: - logger.debug("Failed to send token sms. Missing PASSWORDLESS_MOBILE_NOREPLY_NUMBER.") - return False - except ImportError: - logger.debug("Couldn't import plivo library. Is plivo installed?") - return False - except KeyError: - logger.debug("Couldn't send SMS." - "Did you set your Plivo account tokens?") - except Exception as e: - logger.debug("Failed to send token SMS to user. " - "Possibly no mobile number on user object or the plivo package isn't set up yet. " - "Number entered was {}".format(to_number)) - logger.exception(e) - return False +def send_plivo_sms(to_number, message, code): + from plivo import RestClient + client = RestClient(os.environ["PLIVO_AUTH_ID"], os.environ["PLIVO_AUTH_TOKEN"]) + client.messages.create( + src=api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER, + dst=to_number, + text=message, + ) + return True def create_authentication_token(user): From a53afe988ac7ac8b6af1cf9fe779920f06913063 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Feb 2021 22:10:25 +0000 Subject: [PATCH 10/15] Bump bleach from 3.2.1 to 3.3.0 Bumps [bleach](https://github.com/mozilla/bleach) from 3.2.1 to 3.3.0. - [Release notes](https://github.com/mozilla/bleach/releases) - [Changelog](https://github.com/mozilla/bleach/blob/master/CHANGES) - [Commits](https://github.com/mozilla/bleach/compare/v3.2.1...v3.3.0) Signed-off-by: dependabot[bot] --- Pipfile.lock | 350 ++++++++++++++++++++++++++------------------------- 1 file changed, 179 insertions(+), 171 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 7e929f5..2af3a5f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -18,24 +18,24 @@ "default": { "asgiref": { "hashes": [ - "sha256:a5098bc870b80e7b872bff60bb363c7f2c2c89078759f6c47b53ff8c525a152e", - "sha256:cd88907ecaec59d78e4ac00ea665b03e571cb37e3a0e37b3702af1a9e86c365a" + "sha256:5ee950735509d04eb673bd7f7120f8fa1c9e2df495394992c73234d526907e17", + "sha256:7162a3cb30ab0609f1a4c95938fd73e8604f63bdba516a7f7d64b83ff09478f0" ], - "version": "==3.3.0" + "version": "==3.3.1" }, "certifi": { "hashes": [ - "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", - "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41" + "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", + "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" ], - "version": "==2020.6.20" + "version": "==2020.12.5" }, "chardet": { "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", + "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" ], - "version": "==3.0.4" + "version": "==4.0.0" }, "django": { "hashes": [ @@ -62,24 +62,24 @@ }, "pyjwt": { "hashes": [ - "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e", - "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96" + "sha256:a5c70a06e1f33d81ef25eecd50d50bd30e34de1ca8b2b9fa3fe0daaabcf69bf7", + "sha256:b70b15f89dc69b993d8a8d32c299032d5355c82f9b5b7e851d1a6d706dffe847" ], - "version": "==1.7.1" + "version": "==2.0.1" }, "pytz": { "hashes": [ - "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed", - "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048" + "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da", + "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798" ], - "version": "==2020.1" + "version": "==2021.1" }, "requests": { "hashes": [ - "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b", - "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898" + "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", + "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" ], - "version": "==2.24.0" + "version": "==2.25.1" }, "six": { "hashes": [ @@ -104,10 +104,10 @@ }, "urllib3": { "hashes": [ - "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2", - "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e" + "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", + "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" ], - "version": "==1.25.11" + "version": "==1.26.3" } }, "develop": { @@ -120,139 +120,147 @@ }, "attrs": { "hashes": [ - "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594", - "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc" + "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6", + "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700" ], - "version": "==20.2.0" + "version": "==20.3.0" }, "bleach": { "hashes": [ - "sha256:52b5919b81842b1854196eaae5ca29679a2f2e378905c346d3ca8227c2c66080", - "sha256:9f8ccbeb6183c6e6cddea37592dfb0167485c1e3b13b3363bc325aa8bda3adbd" + "sha256:6123ddc1052673e52bab52cdc955bcb57a015264a1c57d37bea2f6b817af0125", + "sha256:98b3170739e5e83dd9dc19633f074727ad848cbedb6026708c8ac2d3b697a433" ], - "version": "==3.2.1" + "index": "pypi", + "version": "==3.3.0" }, "certifi": { "hashes": [ - "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3", - "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41" + "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", + "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" ], - "version": "==2020.6.20" + "version": "==2020.12.5" }, "cffi": { "hashes": [ - "sha256:005f2bfe11b6745d726dbb07ace4d53f057de66e336ff92d61b8c7e9c8f4777d", - "sha256:09e96138280241bd355cd585148dec04dbbedb4f46128f340d696eaafc82dd7b", - "sha256:0b1ad452cc824665ddc682400b62c9e4f5b64736a2ba99110712fdee5f2505c4", - "sha256:0ef488305fdce2580c8b2708f22d7785ae222d9825d3094ab073e22e93dfe51f", - "sha256:15f351bed09897fbda218e4db5a3d5c06328862f6198d4fb385f3e14e19decb3", - "sha256:22399ff4870fb4c7ef19fff6eeb20a8bbf15571913c181c78cb361024d574579", - "sha256:23e5d2040367322824605bc29ae8ee9175200b92cb5483ac7d466927a9b3d537", - "sha256:2791f68edc5749024b4722500e86303a10d342527e1e3bcac47f35fbd25b764e", - "sha256:2f9674623ca39c9ebe38afa3da402e9326c245f0f5ceff0623dccdac15023e05", - "sha256:3363e77a6176afb8823b6e06db78c46dbc4c7813b00a41300a4873b6ba63b171", - "sha256:33c6cdc071ba5cd6d96769c8969a0531be2d08c2628a0143a10a7dcffa9719ca", - "sha256:3b8eaf915ddc0709779889c472e553f0d3e8b7bdf62dab764c8921b09bf94522", - "sha256:3cb3e1b9ec43256c4e0f8d2837267a70b0e1ca8c4f456685508ae6106b1f504c", - "sha256:3eeeb0405fd145e714f7633a5173318bd88d8bbfc3dd0a5751f8c4f70ae629bc", - "sha256:44f60519595eaca110f248e5017363d751b12782a6f2bd6a7041cba275215f5d", - "sha256:4d7c26bfc1ea9f92084a1d75e11999e97b62d63128bcc90c3624d07813c52808", - "sha256:529c4ed2e10437c205f38f3691a68be66c39197d01062618c55f74294a4a4828", - "sha256:6642f15ad963b5092d65aed022d033c77763515fdc07095208f15d3563003869", - "sha256:85ba797e1de5b48aa5a8427b6ba62cf69607c18c5d4eb747604b7302f1ec382d", - "sha256:8f0f1e499e4000c4c347a124fa6a27d37608ced4fe9f7d45070563b7c4c370c9", - "sha256:a624fae282e81ad2e4871bdb767e2c914d0539708c0f078b5b355258293c98b0", - "sha256:b0358e6fefc74a16f745afa366acc89f979040e0cbc4eec55ab26ad1f6a9bfbc", - "sha256:bbd2f4dfee1079f76943767fce837ade3087b578aeb9f69aec7857d5bf25db15", - "sha256:bf39a9e19ce7298f1bd6a9758fa99707e9e5b1ebe5e90f2c3913a47bc548747c", - "sha256:c11579638288e53fc94ad60022ff1b67865363e730ee41ad5e6f0a17188b327a", - "sha256:c150eaa3dadbb2b5339675b88d4573c1be3cb6f2c33a6c83387e10cc0bf05bd3", - "sha256:c53af463f4a40de78c58b8b2710ade243c81cbca641e34debf3396a9640d6ec1", - "sha256:cb763ceceae04803adcc4e2d80d611ef201c73da32d8f2722e9d0ab0c7f10768", - "sha256:cc75f58cdaf043fe6a7a6c04b3b5a0e694c6a9e24050967747251fb80d7bce0d", - "sha256:d80998ed59176e8cba74028762fbd9b9153b9afc71ea118e63bbf5d4d0f9552b", - "sha256:de31b5164d44ef4943db155b3e8e17929707cac1e5bd2f363e67a56e3af4af6e", - "sha256:e66399cf0fc07de4dce4f588fc25bfe84a6d1285cc544e67987d22663393926d", - "sha256:f0620511387790860b249b9241c2f13c3a80e21a73e0b861a2df24e9d6f56730", - "sha256:f4eae045e6ab2bb54ca279733fe4eb85f1effda392666308250714e01907f394", - "sha256:f92cdecb618e5fa4658aeb97d5eb3d2f47aa94ac6477c6daf0f306c5a3b9e6b1", - "sha256:f92f789e4f9241cd262ad7a555ca2c648a98178a953af117ef7fad46aa1d5591" - ], - "version": "==1.14.3" + "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e", + "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d", + "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a", + "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec", + "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362", + "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668", + "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c", + "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b", + "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06", + "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698", + "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2", + "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c", + "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7", + "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009", + "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03", + "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b", + "sha256:7ef7d4ced6b325e92eb4d3502946c78c5367bc416398d387b39591532536734e", + "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909", + "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53", + "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35", + "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26", + "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b", + "sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01", + "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb", + "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293", + "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd", + "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d", + "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3", + "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d", + "sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e", + "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca", + "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d", + "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775", + "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375", + "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b", + "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b", + "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f" + ], + "version": "==1.14.4" }, "chardet": { "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", + "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" ], - "version": "==3.0.4" + "version": "==4.0.0" }, "coverage": { "hashes": [ - "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516", - "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259", - "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9", - "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097", - "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0", - "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f", - "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7", - "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c", - "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5", - "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7", - "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729", - "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978", - "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9", - "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f", - "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9", - "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822", - "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418", - "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82", - "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f", - "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d", - "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221", - "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4", - "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21", - "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709", - "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54", - "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d", - "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270", - "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24", - "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751", - "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a", - "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237", - "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7", - "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636", - "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8" - ], - "version": "==5.3" + "sha256:03ed2a641e412e42cc35c244508cf186015c217f0e4d496bf6d7078ebe837ae7", + "sha256:04b14e45d6a8e159c9767ae57ecb34563ad93440fc1b26516a89ceb5b33c1ad5", + "sha256:0cdde51bfcf6b6bd862ee9be324521ec619b20590787d1655d005c3fb175005f", + "sha256:0f48fc7dc82ee14aeaedb986e175a429d24129b7eada1b7e94a864e4f0644dde", + "sha256:107d327071061fd4f4a2587d14c389a27e4e5c93c7cba5f1f59987181903902f", + "sha256:1375bb8b88cb050a2d4e0da901001347a44302aeadb8ceb4b6e5aa373b8ea68f", + "sha256:14a9f1887591684fb59fdba8feef7123a0da2424b0652e1b58dd5b9a7bb1188c", + "sha256:16baa799ec09cc0dcb43a10680573269d407c159325972dd7114ee7649e56c66", + "sha256:1b811662ecf72eb2d08872731636aee6559cae21862c36f74703be727b45df90", + "sha256:1ccae21a076d3d5f471700f6d30eb486da1626c380b23c70ae32ab823e453337", + "sha256:2f2cf7a42d4b7654c9a67b9d091ec24374f7c58794858bff632a2039cb15984d", + "sha256:322549b880b2d746a7672bf6ff9ed3f895e9c9f108b714e7360292aa5c5d7cf4", + "sha256:32ab83016c24c5cf3db2943286b85b0a172dae08c58d0f53875235219b676409", + "sha256:3fe50f1cac369b02d34ad904dfe0771acc483f82a1b54c5e93632916ba847b37", + "sha256:4a780807e80479f281d47ee4af2eb2df3e4ccf4723484f77da0bb49d027e40a1", + "sha256:4a8eb7785bd23565b542b01fb39115a975fefb4a82f23d407503eee2c0106247", + "sha256:5bee3970617b3d74759b2d2df2f6a327d372f9732f9ccbf03fa591b5f7581e39", + "sha256:60a3307a84ec60578accd35d7f0c71a3a971430ed7eca6567399d2b50ef37b8c", + "sha256:6625e52b6f346a283c3d563d1fd8bae8956daafc64bb5bbd2b8f8a07608e3994", + "sha256:66a5aae8233d766a877c5ef293ec5ab9520929c2578fd2069308a98b7374ea8c", + "sha256:68fb816a5dd901c6aff352ce49e2a0ffadacdf9b6fae282a69e7a16a02dad5fb", + "sha256:6b588b5cf51dc0fd1c9e19f622457cc74b7d26fe295432e434525f1c0fae02bc", + "sha256:6c4d7165a4e8f41eca6b990c12ee7f44fef3932fac48ca32cecb3a1b2223c21f", + "sha256:6d2e262e5e8da6fa56e774fb8e2643417351427604c2b177f8e8c5f75fc928ca", + "sha256:6d9c88b787638a451f41f97446a1c9fd416e669b4d9717ae4615bd29de1ac135", + "sha256:755c56beeacac6a24c8e1074f89f34f4373abce8b662470d3aa719ae304931f3", + "sha256:7e40d3f8eb472c1509b12ac2a7e24158ec352fc8567b77ab02c0db053927e339", + "sha256:812eaf4939ef2284d29653bcfee9665f11f013724f07258928f849a2306ea9f9", + "sha256:84df004223fd0550d0ea7a37882e5c889f3c6d45535c639ce9802293b39cd5c9", + "sha256:859f0add98707b182b4867359e12bde806b82483fb12a9ae868a77880fc3b7af", + "sha256:87c4b38288f71acd2106f5d94f575bc2136ea2887fdb5dfe18003c881fa6b370", + "sha256:89fc12c6371bf963809abc46cced4a01ca4f99cba17be5e7d416ed7ef1245d19", + "sha256:9564ac7eb1652c3701ac691ca72934dd3009997c81266807aef924012df2f4b3", + "sha256:9754a5c265f991317de2bac0c70a746efc2b695cf4d49f5d2cddeac36544fb44", + "sha256:a565f48c4aae72d1d3d3f8e8fb7218f5609c964e9c6f68604608e5958b9c60c3", + "sha256:a636160680c6e526b84f85d304e2f0bb4e94f8284dd765a1911de9a40450b10a", + "sha256:a839e25f07e428a87d17d857d9935dd743130e77ff46524abb992b962eb2076c", + "sha256:b62046592b44263fa7570f1117d372ae3f310222af1fc1407416f037fb3af21b", + "sha256:b7f7421841f8db443855d2854e25914a79a1ff48ae92f70d0a5c2f8907ab98c9", + "sha256:ba7ca81b6d60a9f7a0b4b4e175dcc38e8fef4992673d9d6e6879fd6de00dd9b8", + "sha256:bb32ca14b4d04e172c541c69eec5f385f9a075b38fb22d765d8b0ce3af3a0c22", + "sha256:c0ff1c1b4d13e2240821ef23c1efb1f009207cb3f56e16986f713c2b0e7cd37f", + "sha256:c669b440ce46ae3abe9b2d44a913b5fd86bb19eb14a8701e88e3918902ecd345", + "sha256:c67734cff78383a1f23ceba3b3239c7deefc62ac2b05fa6a47bcd565771e5880", + "sha256:c6809ebcbf6c1049002b9ac09c127ae43929042ec1f1dbd8bb1615f7cd9f70a0", + "sha256:cd601187476c6bed26a0398353212684c427e10a903aeafa6da40c63309d438b", + "sha256:ebfa374067af240d079ef97b8064478f3bf71038b78b017eb6ec93ede1b6bcec", + "sha256:fbb17c0d0822684b7d6c09915677a32319f16ff1115df5ec05bdcaaee40b35f3", + "sha256:fff1f3a586246110f34dc762098b5afd2de88de507559e63553d7da643053786" + ], + "version": "==5.4" }, "cryptography": { "hashes": [ - "sha256:22f8251f68953553af4f9c11ec5f191198bc96cff9f0ac5dd5ff94daede0ee6d", - "sha256:284e275e3c099a80831f9898fb5c9559120d27675c3521278faba54e584a7832", - "sha256:3e17d02941c0f169c5b877597ca8be895fca0e5e3eb882526a74aa4804380a98", - "sha256:52a47e60953679eea0b4d490ca3c241fb1b166a7b161847ef4667dfd49e7699d", - "sha256:57b8c1ed13b8aa386cabbfde3be175d7b155682470b0e259fecfe53850967f8a", - "sha256:6a8f64ed096d13f92d1f601a92d9fd1f1025dc73a2ca1ced46dcf5e0d4930943", - "sha256:6e8a3c7c45101a7eeee93102500e1b08f2307c717ff553fcb3c1127efc9b6917", - "sha256:7ef41304bf978f33cfb6f43ca13bb0faac0c99cda33693aa20ad4f5e34e8cb8f", - "sha256:87c2fffd61e934bc0e2c927c3764c20b22d7f5f7f812ee1a477de4c89b044ca6", - "sha256:88069392cd9a1e68d2cfd5c3a2b0d72a44ef3b24b8977a4f7956e9e3c4c9477a", - "sha256:8a0866891326d3badb17c5fd3e02c926b635e8923fa271b4813cd4d972a57ff3", - "sha256:8f0fd8b0751d75c4483c534b209e39e918f0d14232c0d8a2a76e687f64ced831", - "sha256:9a07e6d255053674506091d63ab4270a119e9fc83462c7ab1dbcb495b76307af", - "sha256:9a8580c9afcdcddabbd064c0a74f337af74ff4529cdf3a12fa2e9782d677a2e5", - "sha256:bd80bc156d3729b38cb227a5a76532aef693b7ac9e395eea8063ee50ceed46a5", - "sha256:d1cbc3426e6150583b22b517ef3720036d7e3152d428c864ff0f3fcad2b97591", - "sha256:e15ac84dcdb89f92424cbaca4b0b34e211e7ce3ee7b0ec0e4f3c55cee65fae5a", - "sha256:e4789b84f8dedf190148441f7c5bfe7244782d9cbb194a36e17b91e7d3e1cca9", - "sha256:f01c9116bfb3ad2831e125a73dcd957d173d6ddca7701528eff1e7d97972872c", - "sha256:f0e3986f6cce007216b23c490f093f35ce2068f3c244051e559f647f6731b7ae", - "sha256:f2aa3f8ba9e2e3fd49bd3de743b976ab192fbf0eb0348cebde5d2a9de0090a9f", - "sha256:fb70a4cedd69dc52396ee114416a3656e011fb0311fca55eb55c7be6ed9c8aef" - ], - "index": "pypi", - "version": "==3.2" + "sha256:0003a52a123602e1acee177dc90dd201f9bb1e73f24a070db7d36c588e8f5c7d", + "sha256:0e85aaae861d0485eb5a79d33226dd6248d2a9f133b81532c8f5aae37de10ff7", + "sha256:594a1db4511bc4d960571536abe21b4e5c3003e8750ab8365fafce71c5d86901", + "sha256:69e836c9e5ff4373ce6d3ab311c1a2eed274793083858d3cd4c7d12ce20d5f9c", + "sha256:788a3c9942df5e4371c199d10383f44a105d67d401fb4304178020142f020244", + "sha256:7e177e4bea2de937a584b13645cab32f25e3d96fc0bc4a4cf99c27dc77682be6", + "sha256:83d9d2dfec70364a74f4e7c70ad04d3ca2e6a08b703606993407bf46b97868c5", + "sha256:84ef7a0c10c24a7773163f917f1cb6b4444597efd505a8aed0a22e8c4780f27e", + "sha256:9e21301f7a1e7c03dbea73e8602905a4ebba641547a462b26dd03451e5769e7c", + "sha256:9f6b0492d111b43de5f70052e24c1f0951cb9e6022188ebcb1cc3a3d301469b0", + "sha256:a69bd3c68b98298f490e84519b954335154917eaab52cf582fa2c5c7efc6e812", + "sha256:b4890d5fb9b7a23e3bf8abf5a8a7da8e228f1e97dc96b30b95685df840b6914a", + "sha256:c366df0401d1ec4e548bebe8f91d55ebcc0ec3137900d214dd7aac8427ef3030", + "sha256:dc42f645f8f3a489c3dd416730a514e7a91a59510ddaadc09d04224c098d3302" + ], + "version": "==3.3.1" }, "distlib": { "hashes": [ @@ -307,18 +315,18 @@ }, "jeepney": { "hashes": [ - "sha256:3479b861cc2b6407de5188695fa1a8d57e5072d7059322469b62628869b8e36e", - "sha256:d6c6b49683446d2407d2fe3acb7a368a77ff063f9182fe427da15d622adc24cf" + "sha256:7d59b6622675ca9e993a6bd38de845051d315f8b0c72cca3aef733a20b648657", + "sha256:aec56c0eb1691a841795111e184e13cad504f7703b9a64f63020816afa79a8ae" ], "markers": "sys_platform == 'linux'", - "version": "==0.4.3" + "version": "==0.6.0" }, "keyring": { "hashes": [ - "sha256:4e34ea2fdec90c1c43d6610b5a5fafa1b9097db1802948e90caf5763974b8f8d", - "sha256:9aeadd006a852b78f4b4ef7c7556c2774d2432bbef8ee538a3e9089ac8b11466" + "sha256:9acb3e1452edbb7544822b12fd25459078769e560fa51f418b6d00afaa6178df", + "sha256:9f44660a5d4931bdc14c08a1d01ef30b18a7a8147380710d8c9f9531e1f6c3c0" ], - "version": "==21.4.0" + "version": "==22.0.1" }, "mccabe": { "hashes": [ @@ -329,17 +337,17 @@ }, "more-itertools": { "hashes": [ - "sha256:6f83822ae94818eae2612063a5101a7311e68ae8002005b5e05f03fd74a86a20", - "sha256:9b30f12df9393f0d28af9210ff8efe48d10c94f73e5daf886f10c4b0b0b4f03c" + "sha256:8e1a2a43b2f2727425f2b5839587ae37093f19153dc26c0927d1048ff6557330", + "sha256:b3a9005928e5bed54076e6e549c792b306fddfe72b2d1d22dd63d42d5d3899cf" ], - "version": "==8.5.0" + "version": "==8.6.0" }, "packaging": { "hashes": [ - "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8", - "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181" + "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5", + "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a" ], - "version": "==20.4" + "version": "==20.9" }, "pandoc": { "hashes": [ @@ -358,10 +366,10 @@ }, "pkginfo": { "hashes": [ - "sha256:a6a4ac943b496745cec21f14f021bbd869d5e9b4f6ec06918cffea5a2f4b9193", - "sha256:ce14d7296c673dc4c61c759a0b6c14bae34e34eb819c0017bb6ca5b7292c56e9" + "sha256:029a70cb45c6171c329dfc890cde0879f8c52d6f3922794796e06f577bb03db4", + "sha256:9fdbea6495622e022cc72c2e5e1b735218e4ffb2a2a69cde2694a6c1f16afb75" ], - "version": "==1.6.1" + "version": "==1.7.0" }, "pluggy": { "hashes": [ @@ -379,10 +387,10 @@ }, "py": { "hashes": [ - "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2", - "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342" + "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3", + "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a" ], - "version": "==1.9.0" + "version": "==1.10.0" }, "pycodestyle": { "hashes": [ @@ -407,10 +415,10 @@ }, "pygments": { "hashes": [ - "sha256:381985fcc551eb9d37c52088a32914e00517e57f4a21609f48141ba08e193fa0", - "sha256:88a0bbcd659fcb9573703957c6b9cff9fab7295e6e76db54c9d00ae42df32773" + "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435", + "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337" ], - "version": "==2.7.2" + "version": "==2.7.4" }, "pypandoc": { "hashes": [ @@ -458,10 +466,10 @@ }, "requests": { "hashes": [ - "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b", - "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898" + "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", + "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" ], - "version": "==2.24.0" + "version": "==2.25.1" }, "requests-toolbelt": { "hashes": [ @@ -472,11 +480,11 @@ }, "secretstorage": { "hashes": [ - "sha256:15da8a989b65498e29be338b3b279965f1b8f09b9668bd8010da183024c8bff6", - "sha256:b5ec909dde94d4ae2fa26af7c089036997030f0cf0a5cb372b4cccabd81c143b" + "sha256:30cfdef28829dad64d6ea1ed08f8eff6aa115a77068926bcc9f5225d5a3246aa", + "sha256:5c36f6537a523ec5f969ef9fad61c98eb9e017bc601d811e53aa25bece64892f" ], "markers": "sys_platform == 'linux'", - "version": "==3.1.2" + "version": "==3.3.0" }, "setuptools-markdown": { "hashes": [ @@ -495,10 +503,10 @@ }, "toml": { "hashes": [ - "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f", - "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88" + "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", + "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" ], - "version": "==0.10.1" + "version": "==0.10.2" }, "tox": { "hashes": [ @@ -510,10 +518,10 @@ }, "tqdm": { "hashes": [ - "sha256:9ad44aaf0fc3697c06f6e05c7cf025dd66bc7bcb7613c66d85f4464c47ac8fad", - "sha256:ef54779f1c09f346b2b5a8e5c61f96fbcb639929e640e59f8cf810794f406432" + "sha256:4621f6823bab46a9cc33d48105753ccbea671b68bab2c50a9f0be23d4065cb5a", + "sha256:fe3d08dd00a526850568d542ff9de9bbc2a09a791da3c334f3213d8d0bbbca65" ], - "version": "==4.51.0" + "version": "==4.56.0" }, "twine": { "hashes": [ @@ -525,17 +533,17 @@ }, "urllib3": { "hashes": [ - "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2", - "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e" + "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", + "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" ], - "version": "==1.25.11" + "version": "==1.26.3" }, "virtualenv": { "hashes": [ - "sha256:b0011228208944ce71052987437d3843e05690b2f23d1c7da4263fde104c97a2", - "sha256:b8d6110f493af256a40d65e29846c69340a947669eec8ce784fcf3dd3af28380" + "sha256:147b43894e51dd6bba882cf9c282447f780e2251cd35172403745fc381a0a80d", + "sha256:2be72df684b74df0ea47679a7df93fd0e04e72520022c57b479d8f881485dbe3" ], - "version": "==20.1.0" + "version": "==20.4.2" }, "wcwidth": { "hashes": [ From ee6c8f2287ff3aea2f3d2c5ced9b3f4409faf8fb Mon Sep 17 00:00:00 2001 From: Nishant Singh Date: Thu, 18 Mar 2021 16:39:30 +0530 Subject: [PATCH 11/15] Configure token length, max length 6 --- README.md | 2 ++ drfpasswordless/models.py | 3 ++- drfpasswordless/serializers.py | 2 +- drfpasswordless/settings.py | 5 ++++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6fe49a7..329dffd 100644 --- a/README.md +++ b/README.md @@ -323,6 +323,8 @@ DEFAULTS = { # Token Generation Retry Count 'PASSWORDLESS_TOKEN_GENERATION_ATTEMPTS': 3 + # The length of the token to send in email or sms, maximum 6 + 'PASSWORDLESS_TOKEN_LENGTH': 6 } ``` diff --git a/drfpasswordless/models.py b/drfpasswordless/models.py index d09f3fc..b07b16f 100644 --- a/drfpasswordless/models.py +++ b/drfpasswordless/models.py @@ -3,6 +3,7 @@ from django.conf import settings import string from django.utils.crypto import get_random_string +from drfpasswordless.settings import api_settings def generate_hex_token(): return uuid.uuid1().hex @@ -13,7 +14,7 @@ def generate_numeric_token(): Generate a random 6 digit string of numbers. We use this formatting to allow leading 0s. """ - return get_random_string(length=6, allowed_chars=string.digits) + return get_random_string(length=api_settings.PASSWORDLESS_TOKEN_LENGTH, allowed_chars=string.digits) class CallbackTokenManger(models.Manager): diff --git a/drfpasswordless/serializers.py b/drfpasswordless/serializers.py index 6ce1523..1ed61bc 100644 --- a/drfpasswordless/serializers.py +++ b/drfpasswordless/serializers.py @@ -175,7 +175,7 @@ class AbstractBaseCallbackTokenSerializer(serializers.Serializer): email = serializers.EmailField(required=False) # Needs to be required=false to require both. mobile = serializers.CharField(required=False, validators=[phone_regex], max_length=17) - token = TokenField(min_length=6, max_length=6, validators=[token_age_validator]) + token = TokenField(min_length=api_settings.PASSWORDLESS_TOKEN_LENGTH, max_length=api_settings.PASSWORDLESS_TOKEN_LENGTH, validators=[token_age_validator]) def validate_alias(self, attrs): email = attrs.get('email', None) diff --git a/drfpasswordless/settings.py b/drfpasswordless/settings.py index 5b93197..c9bd842 100644 --- a/drfpasswordless/settings.py +++ b/drfpasswordless/settings.py @@ -89,7 +89,10 @@ 'PASSWORDLESS_SMS_CALLBACK': 'drfpasswordless.utils.send_sms_with_callback_token', # Token Generation Retry Count - 'PASSWORDLESS_TOKEN_GENERATION_ATTEMPTS': 3 + 'PASSWORDLESS_TOKEN_GENERATION_ATTEMPTS': 3, + + # The length of the token to send in email or sms, maximum 6 + 'PASSWORDLESS_TOKEN_LENGTH': 6 } # List of settings that may be in string import notation. From 9ed45f6f88c3338e58c743663e5f655c818708de Mon Sep 17 00:00:00 2001 From: Charles Han Date: Wed, 31 Mar 2021 00:09:38 -0700 Subject: [PATCH 12/15] Fix bug where demo tokens are not created --- drfpasswordless/utils.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drfpasswordless/utils.py b/drfpasswordless/utils.py index ba02deb..9f02de5 100644 --- a/drfpasswordless/utils.py +++ b/drfpasswordless/utils.py @@ -40,17 +40,13 @@ def create_callback_token_for_user(user, alias_type, token_type): 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 - ) + 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, From eb8b33c4108f448032273e9c79e7ee9053d238a5 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinin Date: Sat, 25 Sep 2021 18:24:19 +0300 Subject: [PATCH 13/15] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6fe49a7..badc945 100644 --- a/README.md +++ b/README.md @@ -309,16 +309,16 @@ DEFAULTS = { # 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': {}, # configurable function for sending email - 'PASSWORDLESS_EMAIL_CALLBACK': 'drfpasswordless.utils.send_email_with_callback_token' + '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' + 'PASSWORDLESS_SMS_CALLBACK': 'drfpasswordless.utils.send_sms_with_callback_token', # Token Generation Retry Count 'PASSWORDLESS_TOKEN_GENERATION_ATTEMPTS': 3 From 444cdacf8c4714027c8a0ee13bb24a7ea463df7e Mon Sep 17 00:00:00 2001 From: Dmitry Kalinin Date: Thu, 14 Oct 2021 12:46:11 +0300 Subject: [PATCH 14/15] Deleted __init__.py from templates --- drfpasswordless/templates/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 drfpasswordless/templates/__init__.py diff --git a/drfpasswordless/templates/__init__.py b/drfpasswordless/templates/__init__.py deleted file mode 100644 index e69de29..0000000 From d92df3754394c6d365c8bc4abe6651caa80a369c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Chojnowski?= Date: Fri, 10 Dec 2021 21:33:35 +0100 Subject: [PATCH 15/15] [django-4.0] change use of deprecated ugettext_lazy to gettext_lazy --- drfpasswordless/serializers.py | 4 +--- tests/test_verification.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drfpasswordless/serializers.py b/drfpasswordless/serializers.py index 6ce1523..468969a 100644 --- a/drfpasswordless/serializers.py +++ b/drfpasswordless/serializers.py @@ -1,5 +1,5 @@ import logging -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.contrib.auth import get_user_model from django.core.exceptions import PermissionDenied from django.core.validators import RegexValidator @@ -299,5 +299,3 @@ class TokenResponseSerializer(serializers.Serializer): """ token = serializers.CharField(source='key') key = serializers.CharField(write_only=True) - - diff --git a/tests/test_verification.py b/tests/test_verification.py index 179c4de..16a0464 100644 --- a/tests/test_verification.py +++ b/tests/test_verification.py @@ -1,6 +1,6 @@ from rest_framework import status from rest_framework.authtoken.models import Token -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework.test import APITestCase from django.contrib.auth import get_user_model from django.urls import reverse