From ac3e78429a31b4482e970997c00e03102de52e6a Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Wed, 10 Oct 2018 08:47:30 -0700 Subject: [PATCH 1/2] Refactor string to int conversions to use ValueError exception. Update PyDocs in the failures module to describe the return types. --- Failures.py | 152 ++++++++++++++++++-------------- app/AuthToken/controllers.py | 2 +- app/RateLimiting/controllers.py | 4 +- app/__init__.py | 4 +- 4 files changed, 93 insertions(+), 69 deletions(-) diff --git a/Failures.py b/Failures.py index 1f2a780..86f4cde 100644 --- a/Failures.py +++ b/Failures.py @@ -1,101 +1,122 @@ import logging +''' +Failure messages + +These functions provide for a standard return message for all known +and expected error conditions. + +The return payload is a JSON document and an HTTP error code. The JSON +document includes these elements: + + success - boolean + message - a short message that uniquely identifies the error + code - a distrinct return code that allows the client to act on + then specic error condition encountered. + field - optional data element that identified the name of the + data element involved in the error. + data - optional data element that provides an id or key value + for the data set being processed when the error occurred. + +''' def unknown_user_id(id_user): logging.debug('Failures: Unknown user id: %s', id_user) return { - 'success': False, - 'message': 'Unknown user', - 'code': 400, - 'data': id_user - }, 500 + 'success': False, + 'message': 'Unknown user', + 'code': 400, + 'data': id_user + }, 500 def unknown_user_email(email): logging.debug('Failures: Unknown user email: %s', email) return { - 'success': False, - 'message': 'Unknown user', - 'code': 400, - 'data': email - }, 500 + 'success': False, + 'message': 'Unknown user', + 'code': 400, + 'data': email + }, 500 def unknown_user_screen_name(screen_name): logging.debug('Failures: Unknown user by screen name: %s', screen_name) return { - 'success': False, - 'message': 'Unknown user screen name', - 'code': 400, - 'data': screen_name - }, 500 + 'success': False, + 'message': 'Unknown user screen name', + 'code': 400, + 'data': screen_name + }, 500 def email_already_in_use(email): logging.debug('Failures: Email already in use: %s', email) return { - 'success': False, - 'message': 'Email already in use', - 'code': 450, - 'data': email - }, 500 + 'success': False, + 'message': 'Email already in use', + 'code': 450, + 'data': email + }, 500 def email_not_confirmed(email): logging.debug('Failures: Email %s not confirmed', email) return { - 'success': False, - 'message': 'Email not confirmed', - 'code': 430 - }, 401 + 'success': False, + 'message': 'Email not confirmed', + 'code': 430, + 'data': email + }, 401 def user_blocked(email): logging.debug('Failures: User %s blocked', email) return { - 'success': False, - 'message': 'User is blocked', - 'code': 420 - }, 401 + 'success': False, + 'message': 'User is blocked', + 'code': 420, + 'data': email + }, 401 def not_a_number(field, value): logging.error('Failures: Not a valid number: %s -> %s', field, value) return { - 'success': False, - 'message': 'Not a valid number', - 'code': 310, - 'field': field, - 'value': value - }, 400 + 'success': False, + 'message': 'Not a valid number', + 'code': 310, + 'field': field, + 'value': value + }, 400 def passwords_do_not_match(): logging.debug('Failures: Passwords do not match') return { - 'success': False, - 'message': "Password confirm doesn't match", - 'code': 460 - }, 500 + 'success': False, + 'message': "Password confirm doesn't match", + 'code': 460 + }, 500 def password_complexity(): logging.debug('Failures: Password is not complex enough') return { - 'success': False, - 'message': "Password is not complex enough", - 'code': 490 - }, 500 + 'success': False, + 'message': "Password is not complex enough", + 'code': 490 + }, 500 def screen_name_already_in_use(screen_name): logging.debug('Failures: Screen name already in use: %s', screen_name) return { - 'success': False, - 'message': "Screenname already in use", - 'data': screen_name, - 'code': 500 - }, 500 + 'success': False, + 'message': "Screenname already in use", + 'code': 500, + 'data': screen_name + }, 500 def rate_exceeded(time): @@ -106,37 +127,38 @@ def rate_exceeded(time): """ logging.debug('Failures: Rate exceeded') return { - 'success': False, - 'message': 'Insufficient bucket tokens', - 'data': time, - 'code': 470 - }, 500 + 'success': False, + 'message': 'Insufficient bucket tokens', + 'code': 470, + 'data': time + }, 500 def wrong_password(email): logging.debug('Failures: Wrong password for %s', email) return { - 'success': False, - 'message': 'Wrong password', - 'code': 410 + 'success': False, + 'message': 'Wrong password', + 'code': 410, + 'data': email }, 401 def unknown_bucket_type(bucket_type): logging.debug('Failures: Unknown bucket type: %s', bucket_type) return { - 'success': False, - 'message': 'Unknown bucket type', - 'code': 180, - 'data': bucket_type - }, 500 + 'success': False, + 'message': 'Unknown bucket type', + 'code': 180, + 'data': bucket_type + }, 500 def wrong_auth_source(auth_source): logging.debug('Failures: Wrong auth source: %s', auth_source) return { - 'success': False, - 'message': 'Wrong auth source', - 'code': 480, - 'data': auth_source - }, 500 + 'success': False, + 'message': 'Wrong auth source', + 'code': 480, + 'data': auth_source + }, 500 diff --git a/app/AuthToken/controllers.py b/app/AuthToken/controllers.py index 0fb64fa..6887706 100644 --- a/app/AuthToken/controllers.py +++ b/app/AuthToken/controllers.py @@ -39,7 +39,7 @@ def post(self): # Parse numbers try: id_user = int(id_user) - except: + except ValueError: return Failures.not_a_number('idUser', id_user) # Validate user exists, is validated and is not blocked diff --git a/app/RateLimiting/controllers.py b/app/RateLimiting/controllers.py index 989e183..75c889e 100644 --- a/app/RateLimiting/controllers.py +++ b/app/RateLimiting/controllers.py @@ -76,12 +76,12 @@ def get(self, bucket_type, id_user, count): # Parse numbers try: id_user = int(id_user) - except: + except ValueError: return Failures.not_a_number('idUser', id_user) try: count = int(count) - except: + except ValueError: return Failures.not_a_number('count', count) # Validate user exists, is validated and is not blocked diff --git a/app/__init__.py b/app/__init__.py index b2e1777..ace5287 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -24,11 +24,13 @@ app = Flask(__name__) # Application version (major,minor,patch-level) -version = "1.1.8" +version = "1.1.9" """ Change Log +1.1.9 Update failure module to include missing return elements. + 1.1.8 Fail any attempt to reset an account password is the account email address has not yet been confirmed. From ba1a256ba86a82b0df31e6c3c8d87e14f0d97cd4 Mon Sep 17 00:00:00 2001 From: Jim Ewald Date: Wed, 10 Oct 2018 11:46:42 -0700 Subject: [PATCH 2/2] Document the server HTTP result codes and what a client can expect when using the service. --- Failures.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/Failures.py b/Failures.py index 86f4cde..5e234b2 100644 --- a/Failures.py +++ b/Failures.py @@ -16,7 +16,16 @@ data element involved in the error. data - optional data element that provides an id or key value for the data set being processed when the error occurred. - + +The HTTP error code indicates whether the request succeeded or failed. If +the call is successful, the service will return a code 200 and a message +of "OK". + +If the request is unsuccessful and the error is due to faulty client data, +return an HTTP error code of 401 if the user is unknown or authentication fails. +Return an HTTP 500 error if the failure is due to an issue within the server, +such as unable to access the back-end database. + ''' @@ -27,7 +36,7 @@ def unknown_user_id(id_user): 'message': 'Unknown user', 'code': 400, 'data': id_user - }, 500 + }, 400 def unknown_user_email(email): @@ -37,7 +46,7 @@ def unknown_user_email(email): 'message': 'Unknown user', 'code': 400, 'data': email - }, 500 + }, 400 def unknown_user_screen_name(screen_name): @@ -47,7 +56,7 @@ def unknown_user_screen_name(screen_name): 'message': 'Unknown user screen name', 'code': 400, 'data': screen_name - }, 500 + }, 400 def email_already_in_use(email): @@ -57,7 +66,7 @@ def email_already_in_use(email): 'message': 'Email already in use', 'code': 450, 'data': email - }, 500 + }, 400 def email_not_confirmed(email): @@ -77,7 +86,7 @@ def user_blocked(email): 'message': 'User is blocked', 'code': 420, 'data': email - }, 401 + }, 403 def not_a_number(field, value): @@ -97,7 +106,7 @@ def passwords_do_not_match(): 'success': False, 'message': "Password confirm doesn't match", 'code': 460 - }, 500 + }, 400 def password_complexity(): @@ -106,7 +115,7 @@ def password_complexity(): 'success': False, 'message': "Password is not complex enough", 'code': 490 - }, 500 + }, 400 def screen_name_already_in_use(screen_name): @@ -116,7 +125,7 @@ def screen_name_already_in_use(screen_name): 'message': "Screenname already in use", 'code': 500, 'data': screen_name - }, 500 + }, 400 def rate_exceeded(time): @@ -131,7 +140,7 @@ def rate_exceeded(time): 'message': 'Insufficient bucket tokens', 'code': 470, 'data': time - }, 500 + }, 400 def wrong_password(email): @@ -151,7 +160,7 @@ def unknown_bucket_type(bucket_type): 'message': 'Unknown bucket type', 'code': 180, 'data': bucket_type - }, 500 + }, 400 def wrong_auth_source(auth_source):