Makes sure the received data in posts have the proper format and content

This commit is contained in:
Sergi Delgado Segura
2020-03-27 13:59:23 +01:00
parent a19e4f2c2e
commit 50c35a5ac1

View File

@@ -42,6 +42,31 @@ def get_remote_addr():
return remote_addr return remote_addr
# NOTCOVERED: not sure how to monkey path this one. May be related to #77
def get_request_data_json(request):
"""
Gets the content of a json POST request and makes sure ir decodes to a Python dictionary.
Args:
request (:obj:`Request`): the request sent by the user.
Returns:
:obj:`dict`: the dictionary parsed from the json request.
Raises:
:obj:`TypeError`: if the request is not json encoded or it does not decodes to a Python dictionary.
"""
if request.is_json:
request_data = request.get_json()
if isinstance(request_data, dict):
return request_data
else:
raise TypeError("Invalid request content")
else:
raise TypeError("Request is not json encoded")
class API: class API:
""" """
The :class:`API` is in charge of the interface between the user and the tower. It handles and server user requests. The :class:`API` is in charge of the interface between the user and the tower. It handles and server user requests.
@@ -77,11 +102,16 @@ class API:
""" """
remote_addr = get_remote_addr() remote_addr = get_remote_addr()
logger.info("Received register request", from_addr="{}".format(remote_addr)) logger.info("Received register request", from_addr="{}".format(remote_addr))
if request.is_json: # Check that data type and content are correct. Abort otherwise.
request_data = request.get_json() try:
request_data = get_request_data_json(request)
except TypeError as e:
logger.info("Received invalid get_appointment request", from_addr="{}".format(remote_addr))
return abort(HTTP_BAD_REQUEST, e)
client_pk = request_data.get("public_key") client_pk = request_data.get("public_key")
if client_pk: if client_pk:
@@ -97,14 +127,7 @@ class API:
else: else:
rcode = HTTP_BAD_REQUEST rcode = HTTP_BAD_REQUEST
error = "Error {}: public_key not found in register message".format( error = "Error {}: public_key not found in register message".format(errors.REGISTRATION_WRONG_FIELD_FORMAT)
errors.REGISTRATION_WRONG_FIELD_FORMAT
)
response = {"error": error}
else:
rcode = HTTP_BAD_REQUEST
error = "appointment rejected. Request is not json encoded"
response = {"error": error} response = {"error": error}
logger.info("Sending response and disconnecting", from_addr="{}".format(remote_addr), response=response) logger.info("Sending response and disconnecting", from_addr="{}".format(remote_addr), response=response)
@@ -127,15 +150,16 @@ class API:
# Getting the real IP if the server is behind a reverse proxy # Getting the real IP if the server is behind a reverse proxy
remote_addr = get_remote_addr() remote_addr = get_remote_addr()
logger.info("Received add_appointment request", from_addr="{}".format(remote_addr)) logger.info("Received add_appointment request", from_addr="{}".format(remote_addr))
if request.is_json: # Check that data type and content are correct. Abort otherwise.
request_data = request.get_json() try:
request_data = get_request_data_json(request)
# We kind of have the chicken an the egg problem here. Data must be verified and the signature must be except TypeError as e:
# checked: return abort(HTTP_BAD_REQUEST, e)
#
# We kind of have the chicken an the egg problem here. Data must be verified and the signature must be checked:
# - If we verify the data first, we may encounter that the signature is wrong and wasted some time. # - If we verify the data first, we may encounter that the signature is wrong and wasted some time.
# - If we check the signature first, we may need to verify some of the information or expose to build # - If we check the signature first, we may need to verify some of the information or expose to build
# appointments with potentially wrong data, which may be exploitable. # appointments with potentially wrong data, which may be exploitable.
@@ -176,11 +200,6 @@ class API:
) )
response = {"error": error} response = {"error": error}
else:
rcode = HTTP_BAD_REQUEST
error = "appointment rejected. Request is not json encoded"
response = {"error": error}
logger.info("Sending response and disconnecting", from_addr="{}".format(remote_addr), response=response) logger.info("Sending response and disconnecting", from_addr="{}".format(remote_addr), response=response)
return jsonify(response), rcode return jsonify(response), rcode
@@ -204,8 +223,14 @@ class API:
# Getting the real IP if the server is behind a reverse proxy # Getting the real IP if the server is behind a reverse proxy
remote_addr = get_remote_addr() remote_addr = get_remote_addr()
if request.is_json: # Check that data type and content are correct. Abort otherwise.
request_data = request.get_json() try:
request_data = get_request_data_json(request)
except TypeError as e:
logger.info("Received invalid get_appointment request", from_addr="{}".format(remote_addr))
return abort(HTTP_BAD_REQUEST, e)
locator = request_data.get("locator") locator = request_data.get("locator")
try: try:
@@ -243,11 +268,6 @@ class API:
rcode = HTTP_NOT_FOUND rcode = HTTP_NOT_FOUND
response = {"locator": locator, "status": "not_found"} response = {"locator": locator, "status": "not_found"}
else:
rcode = HTTP_BAD_REQUEST
error = "appointment rejected. Request is not json encoded"
response = {"error": error}
return jsonify(response), rcode return jsonify(response), rcode
def get_all_appointments(self): def get_all_appointments(self):