mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-24 00:06:16 -04:00
more input checking
This commit is contained in:
@@ -116,7 +116,7 @@ from app.service.service_senders_schema import (
|
||||
)
|
||||
from app.service.utils import get_guest_list_objects
|
||||
from app.user.users_schema import post_set_permissions_schema
|
||||
from app.utils import get_prev_next_pagination_links, utc_now
|
||||
from app.utils import check_suspicious_id, get_prev_next_pagination_links, utc_now
|
||||
|
||||
service_blueprint = Blueprint("service", __name__)
|
||||
|
||||
@@ -202,6 +202,7 @@ def get_live_services_data():
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>", methods=["GET"])
|
||||
def get_service_by_id(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
if request.args.get("detailed") == "True":
|
||||
data = get_detailed_service(
|
||||
service_id, today_only=request.args.get("today_only") == "True"
|
||||
@@ -217,6 +218,7 @@ def get_service_by_id(service_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/statistics")
|
||||
def get_service_notification_statistics(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
return jsonify(
|
||||
data=get_service_statistics(
|
||||
service_id,
|
||||
@@ -228,12 +230,14 @@ def get_service_notification_statistics(service_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/statistics/<string:start>/<int:days>")
|
||||
def get_service_notification_statistics_by_day(service_id, start, days):
|
||||
check_suspicious_id(service_id)
|
||||
return jsonify(
|
||||
data=get_service_statistics_for_specific_days(service_id, start, int(days))
|
||||
)
|
||||
|
||||
|
||||
def get_service_statistics_for_specific_days(service_id, start, days=1):
|
||||
check_suspicious_id(service_id)
|
||||
# Calculate start and end date range
|
||||
end_date = datetime.strptime(start, "%Y-%m-%d")
|
||||
start_date = end_date - timedelta(days=days - 1)
|
||||
@@ -264,6 +268,7 @@ def get_service_statistics_for_specific_days(service_id, start, days=1):
|
||||
def get_service_notification_statistics_by_day_by_user(
|
||||
service_id, user_id, start, days
|
||||
):
|
||||
check_suspicious_id(service_id, user_id)
|
||||
return jsonify(
|
||||
data=get_service_statistics_for_specific_days_by_user(
|
||||
service_id, user_id, start, int(days)
|
||||
@@ -323,6 +328,7 @@ def create_service():
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>", methods=["POST"])
|
||||
def update_service(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
req_json = request.get_json()
|
||||
fetched_service = dao_fetch_service_by_id(service_id)
|
||||
service_going_live = fetched_service.restricted and not req_json.get(
|
||||
@@ -364,6 +370,8 @@ def update_service(service_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/api-key", methods=["POST"])
|
||||
def create_api_key(service_id=None):
|
||||
if service_id:
|
||||
check_suspicious_id(service_id)
|
||||
fetched_service = dao_fetch_service_by_id(service_id=service_id)
|
||||
valid_api_key = api_key_schema.load(request.get_json(), session=db.session)
|
||||
valid_api_key.service = fetched_service
|
||||
@@ -376,6 +384,7 @@ def create_api_key(service_id=None):
|
||||
"/<uuid:service_id>/api-key/revoke/<uuid:api_key_id>", methods=["POST"]
|
||||
)
|
||||
def revoke_api_key(service_id, api_key_id):
|
||||
check_suspicious_id(service_id, api_key_id)
|
||||
expire_api_key(service_id=service_id, api_key_id=api_key_id)
|
||||
return jsonify(), 202
|
||||
|
||||
@@ -383,6 +392,10 @@ def revoke_api_key(service_id, api_key_id):
|
||||
@service_blueprint.route("/<uuid:service_id>/api-keys", methods=["GET"])
|
||||
@service_blueprint.route("/<uuid:service_id>/api-keys/<uuid:key_id>", methods=["GET"])
|
||||
def get_api_keys(service_id, key_id=None):
|
||||
if key_id:
|
||||
check_suspicious_id(service_id, key_id)
|
||||
else:
|
||||
check_suspicious_id(service_id)
|
||||
dao_fetch_service_by_id(service_id=service_id)
|
||||
|
||||
try:
|
||||
@@ -399,12 +412,14 @@ def get_api_keys(service_id, key_id=None):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/users", methods=["GET"])
|
||||
def get_users_for_service(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
fetched = dao_fetch_service_by_id(service_id)
|
||||
return jsonify(data=[x.serialize() for x in fetched.users])
|
||||
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/users/<user_id>", methods=["POST"])
|
||||
def add_user_to_service(service_id, user_id):
|
||||
check_suspicious_id(service_id, user_id)
|
||||
service = dao_fetch_service_by_id(service_id)
|
||||
user = get_user_by_id(user_id=user_id)
|
||||
if user in service.users:
|
||||
@@ -428,6 +443,7 @@ def add_user_to_service(service_id, user_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/users/<user_id>", methods=["DELETE"])
|
||||
def remove_user_from_service(service_id, user_id):
|
||||
check_suspicious_id(service_id, user_id)
|
||||
service = dao_fetch_service_by_id(service_id)
|
||||
user = get_user_by_id(user_id=user_id)
|
||||
if user not in service.users:
|
||||
@@ -447,6 +463,7 @@ def remove_user_from_service(service_id, user_id):
|
||||
# tables. This is so product owner can pass stories as done
|
||||
@service_blueprint.route("/<uuid:service_id>/history", methods=["GET"])
|
||||
def get_service_history(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
from app.models import ApiKey, Service, TemplateHistory
|
||||
from app.schemas import (
|
||||
api_key_history_schema,
|
||||
@@ -496,6 +513,7 @@ def get_service_history(service_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/notifications", methods=["GET", "POST"])
|
||||
def get_all_notifications_for_service(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
current_app.logger.debug("enter get_all_notifications_for_service")
|
||||
if request.method == "GET":
|
||||
data = notifications_filter_schema.load(request.args)
|
||||
@@ -625,6 +643,7 @@ def get_all_notifications_for_service(service_id):
|
||||
"/<uuid:service_id>/notifications/<uuid:notification_id>", methods=["GET"]
|
||||
)
|
||||
def get_notification_for_service(service_id, notification_id):
|
||||
check_suspicious_id(service_id, notification_id)
|
||||
notification = notifications_dao.get_notification_with_personalisation(
|
||||
service_id,
|
||||
notification_id,
|
||||
@@ -640,6 +659,7 @@ def get_notification_for_service(service_id, notification_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/notifications/monthly", methods=["GET"])
|
||||
def get_monthly_notification_stats(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
# check service_id validity
|
||||
dao_fetch_service_by_id(service_id)
|
||||
|
||||
@@ -672,6 +692,7 @@ def get_monthly_notification_stats(service_id):
|
||||
"/<uuid:service_id>/notifications/<uuid:user_id>/monthly", methods=["GET"]
|
||||
)
|
||||
def get_monthly_notification_stats_by_user(service_id, user_id):
|
||||
check_suspicious_id(service_id, user_id)
|
||||
# check service_id validity
|
||||
dao_fetch_service_by_id(service_id)
|
||||
# user = get_user_by_id(user_id=user_id)
|
||||
@@ -705,6 +726,7 @@ def get_monthly_notification_stats_by_user(service_id, user_id):
|
||||
"/<uuid:service_id>/notifications/<uuid:user_id>/month", methods=["GET"]
|
||||
)
|
||||
def get_single_month_notification_stats_by_user(service_id, user_id):
|
||||
check_suspicious_id(service_id, user_id)
|
||||
# check service_id validity
|
||||
dao_fetch_service_by_id(service_id)
|
||||
|
||||
@@ -734,6 +756,7 @@ def get_single_month_notification_stats_by_user(service_id, user_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/notifications/month", methods=["GET"])
|
||||
def get_single_month_notification_stats_for_service(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
# check service_id validity
|
||||
dao_fetch_service_by_id(service_id)
|
||||
|
||||
@@ -757,6 +780,7 @@ def get_single_month_notification_stats_for_service(service_id):
|
||||
|
||||
|
||||
def get_detailed_service(service_id, today_only=False):
|
||||
check_suspicious_id(service_id)
|
||||
service = dao_fetch_service_by_id(service_id)
|
||||
|
||||
service.statistics = get_service_statistics(service_id, today_only)
|
||||
@@ -764,6 +788,7 @@ def get_detailed_service(service_id, today_only=False):
|
||||
|
||||
|
||||
def get_service_statistics(service_id, today_only, limit_days=7):
|
||||
check_suspicious_id(service_id)
|
||||
# today_only flag is used by the send page to work out if the service will exceed their daily usage by sending a job
|
||||
if today_only:
|
||||
stats = dao_fetch_todays_stats_for_service(service_id)
|
||||
@@ -810,6 +835,7 @@ def get_detailed_services(
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/guest-list", methods=["GET"])
|
||||
def get_guest_list(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
from app.enums import RecipientType
|
||||
|
||||
service = dao_fetch_service_by_id(service_id)
|
||||
@@ -834,6 +860,7 @@ def get_guest_list(service_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/guest-list", methods=["PUT"])
|
||||
def update_guest_list(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
# doesn't commit so if there are any errors, we preserve old values in db
|
||||
dao_remove_service_guest_list(service_id)
|
||||
try:
|
||||
@@ -850,6 +877,7 @@ def update_guest_list(service_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/archive", methods=["POST"])
|
||||
def archive_service(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
"""
|
||||
When a service is archived the service is made inactive, templates are archived and api keys are revoked.
|
||||
There is no coming back from this operation.
|
||||
@@ -866,6 +894,7 @@ def archive_service(service_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/suspend", methods=["POST"])
|
||||
def suspend_service(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
"""
|
||||
Suspending a service will mark the service as inactive and revoke API keys.
|
||||
:param service_id:
|
||||
@@ -881,6 +910,7 @@ def suspend_service(service_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/resume", methods=["POST"])
|
||||
def resume_service(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
"""
|
||||
Resuming a service that has been suspended will mark the service as active.
|
||||
The service will need to re-create API keys
|
||||
@@ -899,6 +929,7 @@ def resume_service(service_id):
|
||||
"/<uuid:service_id>/notifications/templates_usage/monthly", methods=["GET"]
|
||||
)
|
||||
def get_monthly_template_usage(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
try:
|
||||
start_date, end_date = get_calendar_year(int(request.args.get("year", "NaN")))
|
||||
data = fetch_monthly_template_usage_for_service(
|
||||
@@ -924,12 +955,14 @@ def get_monthly_template_usage(service_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/send-notification", methods=["POST"])
|
||||
def create_one_off_notification(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
resp = send_one_off_notification(service_id, request.get_json())
|
||||
return jsonify(resp), 201
|
||||
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/email-reply-to", methods=["GET"])
|
||||
def get_email_reply_to_addresses(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
result = dao_get_reply_to_by_service_id(service_id)
|
||||
return jsonify([i.serialize() for i in result]), 200
|
||||
|
||||
@@ -938,12 +971,14 @@ def get_email_reply_to_addresses(service_id):
|
||||
"/<uuid:service_id>/email-reply-to/<uuid:reply_to_id>", methods=["GET"]
|
||||
)
|
||||
def get_email_reply_to_address(service_id, reply_to_id):
|
||||
check_suspicious_id(service_id, reply_to_id)
|
||||
result = dao_get_reply_to_by_id(service_id=service_id, reply_to_id=reply_to_id)
|
||||
return jsonify(result.serialize()), 200
|
||||
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/email-reply-to/verify", methods=["POST"])
|
||||
def verify_reply_to_email_address(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
email_address = email_data_request_schema.load(request.get_json())
|
||||
|
||||
check_if_reply_to_address_already_in_use(service_id, email_address["email"])
|
||||
@@ -970,6 +1005,7 @@ def verify_reply_to_email_address(service_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/email-reply-to", methods=["POST"])
|
||||
def add_service_reply_to_email_address(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
# validate the service exists, throws ResultNotFound exception.
|
||||
dao_fetch_service_by_id(service_id)
|
||||
form = validate(request.get_json(), add_service_email_reply_to_request)
|
||||
@@ -986,6 +1022,7 @@ def add_service_reply_to_email_address(service_id):
|
||||
"/<uuid:service_id>/email-reply-to/<uuid:reply_to_email_id>", methods=["POST"]
|
||||
)
|
||||
def update_service_reply_to_email_address(service_id, reply_to_email_id):
|
||||
check_suspicious_id(service_id, reply_to_email_id)
|
||||
# validate the service exists, throws ResultNotFound exception.
|
||||
dao_fetch_service_by_id(service_id)
|
||||
form = validate(request.get_json(), add_service_email_reply_to_request)
|
||||
@@ -1003,6 +1040,7 @@ def update_service_reply_to_email_address(service_id, reply_to_email_id):
|
||||
methods=["POST"],
|
||||
)
|
||||
def delete_service_reply_to_email_address(service_id, reply_to_email_id):
|
||||
check_suspicious_id(service_id, reply_to_email_id)
|
||||
archived_reply_to = archive_reply_to_email_address(service_id, reply_to_email_id)
|
||||
|
||||
return jsonify(data=archived_reply_to.serialize()), 200
|
||||
@@ -1010,6 +1048,7 @@ def delete_service_reply_to_email_address(service_id, reply_to_email_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/sms-sender", methods=["POST"])
|
||||
def add_service_sms_sender(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
dao_fetch_service_by_id(service_id)
|
||||
form = validate(request.get_json(), add_service_sms_sender_request)
|
||||
inbound_number_id = form.get("inbound_number_id", None)
|
||||
@@ -1046,6 +1085,7 @@ def add_service_sms_sender(service_id):
|
||||
"/<uuid:service_id>/sms-sender/<uuid:sms_sender_id>", methods=["POST"]
|
||||
)
|
||||
def update_service_sms_sender(service_id, sms_sender_id):
|
||||
check_suspicious_id(service_id, sms_sender_id)
|
||||
form = validate(request.get_json(), add_service_sms_sender_request)
|
||||
|
||||
sms_sender_to_update = dao_get_service_sms_senders_by_id(
|
||||
@@ -1073,6 +1113,7 @@ def update_service_sms_sender(service_id, sms_sender_id):
|
||||
"/<uuid:service_id>/sms-sender/<uuid:sms_sender_id>/archive", methods=["POST"]
|
||||
)
|
||||
def delete_service_sms_sender(service_id, sms_sender_id):
|
||||
check_suspicious_id(service_id, sms_sender_id)
|
||||
sms_sender = archive_sms_sender(service_id, sms_sender_id)
|
||||
|
||||
return jsonify(data=sms_sender.serialize()), 200
|
||||
@@ -1082,6 +1123,8 @@ def delete_service_sms_sender(service_id, sms_sender_id):
|
||||
"/<uuid:service_id>/sms-sender/<uuid:sms_sender_id>", methods=["GET"]
|
||||
)
|
||||
def get_service_sms_sender_by_id(service_id, sms_sender_id):
|
||||
check_suspicious_id(service_id, sms_sender_id)
|
||||
|
||||
sms_sender = dao_get_service_sms_senders_by_id(
|
||||
service_id=service_id, service_sms_sender_id=sms_sender_id
|
||||
)
|
||||
@@ -1090,18 +1133,22 @@ def get_service_sms_sender_by_id(service_id, sms_sender_id):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/sms-sender", methods=["GET"])
|
||||
def get_service_sms_senders_for_service(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
|
||||
sms_senders = dao_get_sms_senders_by_service_id(service_id=service_id)
|
||||
return jsonify([sms_sender.serialize() for sms_sender in sms_senders]), 200
|
||||
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/organization", methods=["GET"])
|
||||
def get_organization_for_service(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
organization = dao_get_organization_by_service_id(service_id=service_id)
|
||||
return jsonify(organization.serialize() if organization else {}), 200
|
||||
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/data-retention", methods=["GET"])
|
||||
def get_data_retention_for_service(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
data_retention_list = fetch_service_data_retention(service_id)
|
||||
return (
|
||||
jsonify([data_retention.serialize() for data_retention in data_retention_list]),
|
||||
@@ -1114,6 +1161,7 @@ def get_data_retention_for_service(service_id):
|
||||
methods=["GET"],
|
||||
)
|
||||
def get_data_retention_for_service_notification_type(service_id, notification_type):
|
||||
check_suspicious_id(service_id)
|
||||
data_retention = fetch_service_data_retention_by_notification_type(
|
||||
service_id, notification_type
|
||||
)
|
||||
@@ -1124,12 +1172,14 @@ def get_data_retention_for_service_notification_type(service_id, notification_ty
|
||||
"/<uuid:service_id>/data-retention/<uuid:data_retention_id>", methods=["GET"]
|
||||
)
|
||||
def get_data_retention_for_service_by_id(service_id, data_retention_id):
|
||||
check_suspicious_id(service_id, data_retention_id)
|
||||
data_retention = fetch_service_data_retention_by_id(service_id, data_retention_id)
|
||||
return jsonify(data_retention.serialize() if data_retention else {}), 200
|
||||
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/data-retention", methods=["POST"])
|
||||
def create_service_data_retention(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
form = validate(request.get_json(), add_service_data_retention_request)
|
||||
try:
|
||||
new_data_retention = insert_service_data_retention(
|
||||
@@ -1152,6 +1202,7 @@ def create_service_data_retention(service_id):
|
||||
"/<uuid:service_id>/data-retention/<uuid:data_retention_id>", methods=["POST"]
|
||||
)
|
||||
def modify_service_data_retention(service_id, data_retention_id):
|
||||
check_suspicious_id(service_id, data_retention_id)
|
||||
form = validate(request.get_json(), update_service_data_retention_request)
|
||||
|
||||
update_count = update_service_data_retention(
|
||||
@@ -1252,5 +1303,6 @@ def check_if_reply_to_address_already_in_use(service_id, email_address):
|
||||
|
||||
@service_blueprint.route("/<uuid:service_id>/notification-count", methods=["GET"])
|
||||
def get_notification_count_for_service_id(service_id):
|
||||
check_suspicious_id(service_id)
|
||||
count = dao_get_notification_count_for_service(service_id=service_id)
|
||||
return jsonify(count=count), 200
|
||||
|
||||
Reference in New Issue
Block a user